package com.ctshk.rpc.order.bus.service.impl;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

import com.ctshk.rpc.order.bus.dto.*;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ctshk.common.dto.Result;
import com.ctshk.common.enums.ApprovalStatus;
import com.ctshk.common.enums.CollectionTypeIdCode;
import com.ctshk.common.enums.IsDeletedCode;
import com.ctshk.common.enums.OrderCollectionStatus;
import com.ctshk.common.enums.OrderPaymentStatus;
import com.ctshk.common.enums.OrderRefundStatus;
import com.ctshk.common.enums.OrderScheduledStatus;
import com.ctshk.common.enums.OrderSource;
import com.ctshk.common.enums.OrderStatus;
import com.ctshk.common.enums.ProductType;
import com.ctshk.common.enums.SalesMethod;
import com.ctshk.common.enums.SupplierConfirmStatus;
import com.ctshk.common.enums.SysApprovalType;
import com.ctshk.common.enums.SystemBusinessType;
import com.ctshk.common.enums.SystemError;
import com.ctshk.common.enums.bus.BusConst;
import com.ctshk.common.exception.BusinessException;
import com.ctshk.common.exception.CtsException;
import com.ctshk.common.model.PageResponse;
import com.ctshk.common.model.TokenUser;
import com.ctshk.common.req.OperationByIdReq;
import com.ctshk.common.req.OperationPageByIdReq;
import com.ctshk.common.service.support.BaseService;
import com.ctshk.common.utils.Assist;
import com.ctshk.common.utils.BConst;
import com.ctshk.common.utils.DateUtil;
import com.ctshk.common.utils.EntityUtil;
import com.ctshk.common.utils.HktOrderUtil;
import com.ctshk.common.utils.OperateNumberGenerateUtil;
import com.ctshk.common.utils.RlgOrderUtil;
import com.ctshk.common.utils.SnowflakeIdWorker;
import com.ctshk.common.vo.OrderRefundDTO;
import com.ctshk.rpc.booking.enums.SupplierReserveTypeEnum;
import com.ctshk.rpc.booking.req.system.SupplierOrderSystemFreeCallConfirmReq;
import com.ctshk.rpc.booking.req.system.bus.add.SupplierOrderSystemBusAddReq;
import com.ctshk.rpc.booking.req.system.bus.add.SupplierSystemOrderBusAddReq;
import com.ctshk.rpc.booking.req.system.bus.add.SupplierSystemOrderBusTicketAddReq;
import com.ctshk.rpc.booking.service.ISupplierOrderService;
import com.ctshk.rpc.bus.dto.BusLineDTO;
import com.ctshk.rpc.bus.dto.BusPriceRemainderDTO;
import com.ctshk.rpc.bus.dto.BusProductCostPriceFullInfoDTO;
import com.ctshk.rpc.bus.dto.BusProductDTO;
import com.ctshk.rpc.bus.dto.BusProductReservationSettingsDTO;
import com.ctshk.rpc.bus.service.IBusLineService;
import com.ctshk.rpc.bus.service.IBusProductCostPriceService;
import com.ctshk.rpc.bus.service.IBusProductReservationSettingsService;
import com.ctshk.rpc.bus.service.IBusProductSeatService;
import com.ctshk.rpc.bus.service.IBusProductService;
import com.ctshk.rpc.finance.req.bill.BillAddCollectionReq;
import com.ctshk.rpc.finance.req.bill.BillOperateRefundReq;
import com.ctshk.rpc.finance.req.onaccount.UseQuotaReq;
import com.ctshk.rpc.finance.service.IFinanceBillService;
import com.ctshk.rpc.finance.service.IFinanceOnAccountCurrencyQuotaService;
import com.ctshk.rpc.insurance.dto.InsuranceDTO;
import com.ctshk.rpc.insurance.dto.InsuranceInsuredDTO;
import com.ctshk.rpc.insurance.dto.OfferDTO;
import com.ctshk.rpc.insurance.req.InsuranceUnderwritingReq;
import com.ctshk.rpc.insurance.req.taiping.PlanConsult;
import com.ctshk.rpc.insurance.req.tp.AcceptUnderReq;
import com.ctshk.rpc.insurance.req.tp.ApplicantInfo;
import com.ctshk.rpc.insurance.req.tp.InsuredInfo;
import com.ctshk.rpc.insurance.req.tp.Offer;
import com.ctshk.rpc.insurance.req.tp.OfferReq;
import com.ctshk.rpc.insurance.service.IInsuranceService;
import com.ctshk.rpc.iotc.dto.OperateBankPreferenceQueryDTO;
import com.ctshk.rpc.iotc.dto.OperatePromotionQueryDTO;
import com.ctshk.rpc.iotc.req.OperateBankConformQueryReq;
import com.ctshk.rpc.iotc.req.OperateBankDeductReq;
import com.ctshk.rpc.iotc.req.OperatePromotionConformReq;
import com.ctshk.rpc.iotc.req.OperatePromotionDeductReq;
import com.ctshk.rpc.iotc.service.IOperateBankPreferenceService;
import com.ctshk.rpc.iotc.service.IOperatePromotionService;
import com.ctshk.rpc.order.bus.entity.BusManualOrder;
import com.ctshk.rpc.order.bus.entity.BusOrder;
import com.ctshk.rpc.order.bus.entity.BusOrderCollection;
import com.ctshk.rpc.order.bus.entity.BusOrderCost;
import com.ctshk.rpc.order.bus.entity.BusOrderInsurance;
import com.ctshk.rpc.order.bus.entity.BusOrderReceipt;
import com.ctshk.rpc.order.bus.entity.BusOrderRefund;
import com.ctshk.rpc.order.bus.entity.BusOrderTourist;
import com.ctshk.rpc.order.bus.mapper.BusManualOrderMapper;
import com.ctshk.rpc.order.bus.mapper.BusOrderCollectionMapper;
import com.ctshk.rpc.order.bus.mapper.BusOrderCostMapper;
import com.ctshk.rpc.order.bus.mapper.BusOrderInsuranceMapper;
import com.ctshk.rpc.order.bus.mapper.BusOrderMapper;
import com.ctshk.rpc.order.bus.mapper.BusOrderReceiptMapper;
import com.ctshk.rpc.order.bus.mapper.BusOrderRefundMapper;
import com.ctshk.rpc.order.bus.mapper.BusOrderTouristMapper;
import com.ctshk.rpc.order.bus.req.BusBusOrderConfirmReq;
import com.ctshk.rpc.order.bus.req.BusCancelOrderReq;
import com.ctshk.rpc.order.bus.req.BusOrderCancelB2CReq;
import com.ctshk.rpc.order.bus.req.BusOrderCancelHandleReq;
import com.ctshk.rpc.order.bus.req.BusOrderCreateB2CReq;
import com.ctshk.rpc.order.bus.req.BusOrderCreateHandleReq;
import com.ctshk.rpc.order.bus.req.BusOrderOrderInformTouristReq;
import com.ctshk.rpc.order.bus.req.BusOrderPageReq;
import com.ctshk.rpc.order.bus.req.BusOrderPayB2CReq;
import com.ctshk.rpc.order.bus.req.BusOrderPayHandleReq;
import com.ctshk.rpc.order.bus.req.BusOrderPaymentReq;
import com.ctshk.rpc.order.bus.req.BusOrderRefundCancelReq;
import com.ctshk.rpc.order.bus.req.BusOrderSupplieConfirmReq;
import com.ctshk.rpc.order.bus.req.BusOrderTouristReq;
import com.ctshk.rpc.order.bus.req.BusPayOrderCollectionReq;
import com.ctshk.rpc.order.bus.req.BusPlaceOrderInsuranceReq;
import com.ctshk.rpc.order.bus.req.BusPlaceOrderReq;
import com.ctshk.rpc.order.bus.req.BusRefreshByConfirmOrderReq;
import com.ctshk.rpc.order.bus.service.IBusOrderService;
import com.ctshk.rpc.system.dto.MainDataCurrencyListDTO;
import com.ctshk.rpc.system.dto.MainDataCurrencyQueryDTO;
import com.ctshk.rpc.system.dto.MainDataManualSystemDTO;
import com.ctshk.rpc.system.dto.SysDepartmentDTO;
import com.ctshk.rpc.system.dto.UserDTO;
import com.ctshk.rpc.system.dto.member.ContactQueryDTO;
import com.ctshk.rpc.system.enums.CrmMemberProductPointsRateEnum;
import com.ctshk.rpc.system.req.MainDataCurrencyListReq;
import com.ctshk.rpc.system.req.MainDataCurrencyUpdateStatusReq;
import com.ctshk.rpc.system.req.crm.member.CrmMemberQueryReq;
import com.ctshk.rpc.system.req.crm.member.CrmMemberUpdatePointsReq;
import com.ctshk.rpc.system.service.ICrmMemberService;
import com.ctshk.rpc.system.service.IMainDataCurrencyService;
import com.ctshk.rpc.system.service.IMainDataManualSystemService;
import com.ctshk.rpc.system.service.ISysDepartmentService;
import com.ctshk.rpc.system.service.ISysPermissionService;
import com.ctshk.rpc.system.service.ISysUserService;
import com.ctshk.rpc.workflow.service.ISysApprovalService;

import lombok.extern.slf4j.Slf4j;

/**
 * <p>
 * 巴士订单表 服务实现类
 * </p>
 *
 * @author 彭柳霖
 * @since 2021-02-24
 */
@Slf4j
@DubboService
public class BusOrderServiceImpl extends ServiceImpl<BusOrderMapper, BusOrder> implements IBusOrderService, BaseService {

    @Autowired
    private BusOrderMapper busOrderMapper;
    @Autowired
    private BusOrderTouristMapper busOrderTouristMapper;
    @Autowired
    private BusOrderCollectionMapper busOrderCollectionMapper;

    @Autowired
    private BusManualOrderMapper busManualOrderMapper;

    @Autowired
    private BusOrderRefundMapper busOrderRefundMapper;

    @Autowired
    private BusOrderReceiptMapper busOrderReceiptMapper;

    @DubboReference
    private IMainDataCurrencyService iMainDataCurrencyService;

    @DubboReference
    private IBusLineService busLineService;

    @DubboReference
    private IBusProductService busProductService;

    @DubboReference
    ICrmMemberService crmMemberService;

    @DubboReference
    ISysDepartmentService sysDepartmentService;

    @DubboReference
    ISysUserService sysUserService;

    @DubboReference
    IOperateBankPreferenceService operateBankPreferenceService;

    @DubboReference
    IOperatePromotionService operatePromotionService;

    @DubboReference
    IMainDataCurrencyService mainDataCurrencyService;

    @DubboReference
    ISysApprovalService sysApprovalService;
    
    @DubboReference
    ISupplierOrderService supplierOrderService;
    
    @DubboReference
    IBusProductCostPriceService busProductCostPriceService;
    
    @Autowired
    BusOrderCostMapper busOrderCostMapper;
    
    @DubboReference
    IBusProductReservationSettingsService busProductReservationSettingsService;
    
    @DubboReference
    IFinanceBillService iFinanceBillService;
    
    @DubboReference
    IInsuranceService iInsuranceService;
    
    @DubboReference
    IBusProductSeatService busProductSeatService;
    
    @DubboReference
    IMainDataManualSystemService mainDataManualSystemService;
    
    @Autowired
    BusOrderInsuranceMapper busOrderInsuranceMapper;
    
    @DubboReference
    ISysPermissionService sysPermissionService;
    
    @DubboReference
    IFinanceOnAccountCurrencyQuotaService financeOnAccountCurrencyQuotaService;
    
    /**
     * 填写订单信息下单
     * @param req
     * @param user
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Result addBusOrder(BusPlaceOrderReq req, Long userId){
    	BusOrderCreateHandleReq handleReq = toBean(req, BusOrderCreateHandleReq.class);
    	
    	//线下代理
    	if (BusConst.CLIENT_TYPE_AGENT.equals(req.getClientType())) {
    		handleReq.setOrderSource(OrderSource.CPM_PROXY.getCode());
    		handleReq.setStrategyType(2);
    		handleReq.setRelId(req.getAgencyId());;
    	} else {  //线下自营
    		handleReq.setOrderSource(OrderSource.CPM.getCode());
    		handleReq.setStrategyType(1);
    		handleReq.setRelId(userId);
    	}
    	
    	UserDTO userDTO = sysUserService.queryCacheUser(userId);
    	validateNotNull(userDTO);
    	
    	handleReq.setUserId(userDTO.getId());
    	handleReq.setSalesmanId(userDTO.getId());
    	handleReq.setSalesmanName(Assist.join(userDTO.getUsername(), "/", userDTO.getDept()));
    	
    	return createOrderHandle(handleReq, req.getInsuranceReq(), req.getBusOrderTouristReqList());
    }
    
    /**
     * B2C填写订单信息
     * @return
     */
    @Transactional
    @Override
    public Result<Long> addBusOrderB2C(BusOrderCreateB2CReq req, Long userId) {
    	validateArgs(req);
    	
    	BusOrderCreateHandleReq handleReq = toBean(req, BusOrderCreateHandleReq.class);
    	
    	handleReq.setStrategyType(3);
    	handleReq.setRelId(req.getChannelId());
    	handleReq.setUserId(userId);
    	handleReq.setClientType(BusConst.CLIENT_TYPE_COMM);
    	
    	//暂时写死
    	handleReq.setSalesmanId(1344284712813568l);
    	handleReq.setSalesmanName("admin/中旅旅行");
    	
    	return createOrderHandle(handleReq, null, req.getBusOrderTouristReqList());
    }
    
    /**
     * 创建订单逻辑处理
     * @param source 订单来源
     */
    private Result<Long> createOrderHandle(BusOrderCreateHandleReq req, BusPlaceOrderInsuranceReq insuranceReq, List<BusOrderTouristReq> busOrderTouristReqList) {
    	validateArgs(req);
    	Long userId = req.getUserId();
    	BusProductDTO busProductDTO = busProductService.queryDetail(req.getBusProductId());
        if(Objects.isNull(busProductDTO)){
            return Result.failed(SystemError.BUS_PRODUCT_9009);
        }
        
        //默认散客
        if (req.getClientType() == null) {
        	req.setClientType(BusConst.CLIENT_TYPE_COMM);
        }
        if (req.getAdultNum() == null) {
        	req.setAdultNum(0);
        }
        if (req.getChildrenNum() == null) {
        	req.setChildrenNum(0);
        }
        if (req.getOldNum() == null) {
        	req.setOldNum(0);
        }
        
        BusOrder busOrder = EntityUtil.copy(req, BusOrder.class);
        busOrder.setBusId(req.getBusProductId());
        Long id = SnowflakeIdWorker.nextId();
        busOrder.setId(id);
        busOrder.setDepartureCityId(busProductDTO.getDepartureCityId());
        busOrder.setDepartureCityName(busProductDTO.getDepartureCityName());
        busOrder.setArriveCityId(busProductDTO.getArriveCityId());
        busOrder.setArriveCityName(busProductDTO.getArriveCityName());
        busOrder.setLineId(busProductDTO.getLineId());
        busOrder.setLineName(busProductDTO.getLineName());
        busOrder.setShiftCode(busProductDTO.getShiftCode());
        busOrder.setBoardingStationId(busProductDTO.getBoardingStationId());
        busOrder.setBoardingStationName(busProductDTO.getBoardingStationName());
        busOrder.setAlightingStationId(busProductDTO.getAlightingStationId());
        busOrder.setAlightingStationName(busProductDTO.getAlightingStationName());
        busOrder.setBusCompaniesId(busProductDTO.getBusCompaniesId());
        busOrder.setBusCompaniesName(busProductDTO.getBusCompaniesName());
        busOrder.setProductType(busProductDTO.getProductSource());
        busOrder.setSource(req.getOrderSource());
        //是否代理
        busOrder.setIsAgent(req.getStrategyType() == 2 ? 1 : 0);
        
        LocalDateTime nowLocalDateTime = LocalDateTime.now();
        int touristNumber = busOrderTouristReqList.size();

        //旅客类型成本ID关系map
        Map<String, Long> touristTypeCostIdMap = new HashMap<>();
        BigDecimal costRate = null;
        //巴士产品价格完整信息
        List<BusProductCostPriceFullInfoDTO> costPriceFullInfoList = busProductCostPriceService.queryFullInfoList(req.getBusProductId(), req.getEffectiveTime());
        notNull(costPriceFullInfoList, SystemError.BUS_PRODUCT_9037);
        for (BusProductCostPriceFullInfoDTO costPriceFullInfo : costPriceFullInfoList) {
        	Long currencyId = costPriceFullInfo.getCurrencyId();
        	BusOrderCost busOrderCost = newCreateEntityUserId(BusOrderCost.class, null, userId);
        	busOrderCost.setOrderId(busOrder.getId());
        	busOrderCost.setCostPrice(costPriceFullInfo.getPrice());
        	busOrderCost.setCostCurrencyId(currencyId);
        	busOrderCost.setCostCurrency(costPriceFullInfo.getCurrencyName());
        	busOrderCost.setTouristType(Assist.toInteger(costPriceFullInfo.getPassengerId()));

        	if (costRate == null) {
        		validateNotNull(currencyId);

        		//非HKD转换汇率
        		if (!BusConst.CURRENCY_ID_HKD.equals(costPriceFullInfo.getCurrencyId())) {
        			costRate = mainDataCurrencyService.getMarketRateById(currencyId);
        			notNull(costRate, SystemError.AIREXPRESS_ORDER_60029);
        		} else {
        			costRate = BigDecimal.ONE;
        		}
        		busOrderCost.setCostExchangeRate(costRate);
        	}
        	busOrderCostMapper.insert(busOrderCost);

        	touristTypeCostIdMap.put(Assist.toString(costPriceFullInfo.getPassengerId()), busOrderCost.getId());
        }
        
        //根据不同渠道查询产品售价信息
        BusPriceRemainderDTO busPriceRemainderDTO = busProductService.findBusSalePriceInfoHandle(req.getStrategyType(), req.getBusProductId(), req.getEffectiveTime(), req.getRelId());
        
    	//成人价
    	BigDecimal adultPrice = busPriceRemainderDTO.getAdultPrice();
    	//小童价
    	BigDecimal childrenPrice = busPriceRemainderDTO.getChildrenPrice();
    	//长者价
    	BigDecimal oldPrice = busPriceRemainderDTO.getChildrenPrice();
        
    	//非API产品
        if (!ProductType.API_PRODUCT.getCode().equals(busOrder.getProductType())) {
        	//保存巴士产品已售信息
        	busProductService.saveProductSold(busPriceRemainderDTO, touristNumber, userId);
        }
        
        //添加订单信息
        List<BusOrderTourist> busOrderTouristList = EntityUtil.copyList(busOrderTouristReqList, BusOrderTourist.class);
        fillCreateEntityUserId(busOrderTouristList, userId);
        int allTouristNum = req.getAdultNum() + req.getChildrenNum() + req.getOldNum();
        if (allTouristNum != busOrderTouristList.size()) {
        	throw new RuntimeException("旅客数量不相等");
        }

        //后期去掉，旅客类型由前端传
        for (int i = 0; i < busOrderTouristList.size(); i++) {
        	BusOrderTourist touristEntity = busOrderTouristList.get(i);
        	if (Assist.isBlank(touristEntity.getTouristType())) {
        		if (i < req.getAdultNum()) {
        			touristEntity.setTouristType("1");
        		} else if (i < req.getAdultNum() + req.getChildrenNum()) {
        			touristEntity.setTouristType("2");
        		} else {
        			touristEntity.setTouristType("3");
        		}
        	}
        }
        
        //保险相关逻辑
        BusOrderInsurance busOrderInsurance = addBusOrderForInsurance(insuranceReq, busOrderTouristList, userId, busOrder, req);

        //订单总价
        BigDecimal orderAmount = BigDecimal.ZERO;
        //旅客价格
        orderAmount = Assist.add(orderAmount, Assist.multiply(adultPrice, req.getAdultNum()));
        orderAmount = Assist.add(orderAmount, Assist.multiply(childrenPrice, req.getChildrenNum()));
        orderAmount = Assist.add(orderAmount, Assist.multiply(oldPrice, req.getOldNum()));
        //保险价格
        if (busOrderInsurance != null) {
        	orderAmount = Assist.add(orderAmount, busOrderInsurance.getTotalAmount());
        }
        
        // 计算应收金额
        busOrder.setReceivableAmount(orderAmount);
        
        //获取巴士订单编号
        busOrder.setOrderNumber(buildOrderNumber(req.getSalesmanId(), nowLocalDateTime));
        // 计算付款到期时间,+30分钟
        busOrder.setPayExpireDate(nowLocalDateTime.plusMinutes(30));

        
        busOrder.setOrderAmount(orderAmount);
        busOrder.setNumber(touristNumber);
        busOrder.setContactName(busOrder.getSurname() + busOrder.getName());
//        busOrder.setScheduledStatus(1); //待確認
        busOrder.setPaymentStatus(1); //待付款
//        busOrder.setCancelStatus(0); //未取消
        busOrder.setSalesmanId(req.getSalesmanId());
        busOrder.setSalesmanName(req.getSalesmanName());
        busOrder.setSalesMethods(1);//销售方式(1：单品销售 2：打包销售)
        busOrder.setIsDeleted(IsDeletedCode.NO.getCode());
        busOrder.setCreateId(userId);
        busOrder.setGmtCreate(nowLocalDateTime);
        busOrder.setGmtModified(nowLocalDateTime);
        
        //只有手工产品才维护座位
        if (ProductType.MANUAL_ENTRY.getCode().equals(busProductDTO.getProductSource())) {
        	//所有座位号
        	Set<String> allSeatSet = Assist.defaultSet(busProductSeatService.querySeatListByProduct(busOrder.getBusId()));
        	//已用座号
        	Set<String> usedSeatSet = Assist.defaultSet(busOrderTouristMapper.querySeatListByProduct(busOrder.getBusId(), req.getEffectiveTime()));
        	allSeatSet.removeAll(usedSeatSet);
        	if (allSeatSet.size() < busOrderTouristList.size()) {
        		throw new BusinessException(SystemError.BUS_PRODUCT_9036);
        	}
        	List<String> allSeatList = Assist.toList(allSeatSet);
        	
        	for (int i = 0; i < busOrderTouristList.size(); i++) {
        		busOrderTouristList.get(i).setSeatsNumber(allSeatList.get(i));
        	}
        }
        
        /** API产品锁位 */
        if(ProductType.API_PRODUCT.getCode().equals(busProductDTO.getProductSource())){
        	//中汽锁位
        	if (busProductDTO.getBusCompaniesId().equals(BusConst.COMPANIES_ID_RGL)){
        		lockseatRgl(busOrder, req, busProductDTO, busOrderTouristList);
        	} else if(busProductDTO.getBusCompaniesId().equals(BusConst.COMPANIES_ID_HKT)){  //中港通锁位
        		lockseatHkt(busOrder, req, busProductDTO, busOrderTouristList);
        	}
        }

        for (BusOrderTourist tourist : busOrderTouristList) {
        	tourist.setOrderId(id);
        	tourist.setCostId(touristTypeCostIdMap.get(tourist.getTouristType()));

        	//成人
        	if ("1".equals(tourist.getTouristType())) {
        		tourist.setPrice(adultPrice);
        	} else if ("2".equals(tourist.getTouristType())) {  //小童
        		tourist.setPrice(childrenPrice);
        	} else if ("3".equals(tourist.getTouristType())) {  //长者
        		tourist.setPrice(oldPrice);
        	}
        	busOrderTouristMapper.insert(tourist);
        };
        
        busOrderMapper.insert(busOrder);
        
        return Result.success(busOrder.getId());
	}
    
    /**
     * 锁位 - 中汽
     */
    private void lockseatRgl(BusOrder busOrder, BusOrderCreateHandleReq req, BusProductDTO busProductDTO, List<BusOrderTourist> busOrderTouristList) {
    	//中汽票号
        List<String> rglTicketNumList = new ArrayList<>();
        //成人
        if (req.getAdultNum() > 0) {
        	rglTicketNumList.add("4-" + req.getAdultNum());
        } 
        //小童
        if (req.getChildrenNum() > 0) {  
        	rglTicketNumList.add("1-" + req.getChildrenNum());
        } 
        //长者
        if (req.getOldNum() > 0) {  
        	rglTicketNumList.add("2-" + req.getOldNum());
        }
        
        //中汽巴士锁位接口
        Map<String, Object> lockMap = new HashMap<>();
        lockMap.put("busNo", busProductDTO.getShiftCode());//班次码
        lockMap.put("ticketNumStr", Assist.join(rglTicketNumList, ","));
        lockMap.put("departureCityNo", busProductDTO.getThirdDepartureCityId());//出发城市id
        lockMap.put("arrivalCityNo", busProductDTO.getThirdArriveCityId());//到达城市id
        lockMap.put("onStationNo", busProductDTO.getThirdBoardingStationId());
        lockMap.put("offStationNo", busProductDTO.getThirdAlightingStationId());
        lockMap.put("userNickName", req.getContactName());
        lockMap.put("userTelNo", req.getContactMobile());
        
        try {
        	Map<String, Object> resultMap = RlgOrderUtil.lockseat(lockMap, busOrder.getEffectiveTime());
        	busOrder.setThirdTicketNo((String) resultMap.get("orderNo"));
        	List<String> ticketNumList = (List<String>) resultMap.get("ticketNumList");
        	if (Assist.isNotEmpty(ticketNumList)) {
        		for (int i = 0; i < ticketNumList.size(); i++) {
        			if (i < busOrderTouristList.size()) {
        				busOrderTouristList.get(i).setSeatsNumber(ticketNumList.get(i));
        			}
        		}
        	}
		} catch (Exception e) {
			getLogger().error("中汽巴士接口锁位异常 [orderId : {}]", busOrder.getId(), e);
			throw new BusinessException(SystemError.BUS_ORDER_9016);
		}
	}

    /**
     * 锁位 - 中港通
     */
    private void lockseatHkt(BusOrder busOrder, BusOrderCreateHandleReq req, BusProductDTO busProductDTO, List<BusOrderTourist> busOrderTouristList) {
    	//中港通巴士接口锁位
        Map<String, String> lockMap = new HashMap<>();
        lockMap.put("currency_id","1");
        lockMap.put("departure_origin_id", busProductDTO.getThirdBoardingStationId());
        lockMap.put("departure_destination_id", busProductDTO.getThirdAlightingStationId());
        lockMap.put("passenger_tels",req.getContactMobile());
        lockMap.put("passengers",req.getContactName());
        lockMap.put("ticket_category_line_id",busProductDTO.getTicketCategoryId());
        lockMap.put("numbers",String.valueOf(busOrderTouristList.size()));
        lockMap.put("departure_run_id",busProductDTO.getShiftCode());
        Map<String,Object> resultMap = null;
        try{
        	List<Map> orderDetailList = null;
        	resultMap = HktOrderUtil.reservations(lockMap);
        	String orderNo = (String) resultMap.get("orderNo");
        	if (Assist.isBlank(orderNo)) {
        		throw new CtsException("中港通锁位，订单号为空");
        	}
        	busOrder.setThirdTicketNo(orderNo);
        	
        	if (resultMap != null) {
            	Object orderDetailObj = resultMap.get("orderDetailLst");
            	if (orderDetailObj != null) {
            		orderDetailList = new ArrayList<>();
            		if (orderDetailObj instanceof Map) {
            			orderDetailList.add((Map) orderDetailObj);
            		} else {
            			orderDetailList.addAll((List<Map>)orderDetailObj);
            		}
            		
            		resultMap.put("orderDetailLst", orderDetailList);
            	}
            }
        	
        	if (Assist.isEmpty(orderDetailList)) {
        		throw new CtsException("中港通锁位，结果列表为空");
        	}
        	
        	for (int i = 0; i < orderDetailList.size(); i++) {
        		Map orderDetail = orderDetailList.get(i);
        		if (orderDetail != null) {
        			if (i < busOrderTouristList.size()) {
        				busOrderTouristList.get(i).setSeatsNumber((String) orderDetailList.get(i).get("seats"));
        			}
        		}
			}
        }catch (Exception e){
        	getLogger().error("中港通巴士接口锁位异常 [orderId : {}] [result : {}]", busOrder.getId(), toJson(resultMap), e);
			throw new BusinessException(SystemError.BUS_ORDER_9016);
        }
    }
    
    /**
     * 创建订单 - 保险相关逻辑
     */
    private BusOrderInsurance addBusOrderForInsurance(BusPlaceOrderInsuranceReq insuranceReq, List<BusOrderTourist> busOrderTouristList
    		, Long userId, BusOrder busOrder, BusOrderCreateHandleReq handleReq) {
    	if (insuranceReq == null) 
    		return null;
    	List<Integer> insuranceTouristIndexList = insuranceReq.getInsuranceTouristIndexList();
    	
    	BusOrderInsurance insuranceEntity = newCreateEntityUserId(BusOrderInsurance.class, insuranceReq, userId);

    	insuranceEntity.setOrderId(busOrder.getId());
    	insuranceEntity.setBeginDate(busOrder.getEffectiveTime());
    	insuranceEntity.setEndDate(busOrder.getEffectiveTime());
    	insuranceEntity.setDeparturePlace(busOrder.getDepartureCityName());
    	insuranceEntity.setDestination(busOrder.getArriveCityName());
    	insuranceEntity.setDays(1);
    	insuranceEntity.setCurrencyId(1365184144700788737l);
    	insuranceEntity.setCurrency("HKD");
    	insuranceEntity.setPeopleNumber(Assist.size(insuranceTouristIndexList));

    	//保险信息
    	InsuranceDTO insuranceDto = notNull(iInsuranceService.detail(insuranceReq.getInsuranceId()), SystemError.CUSTOM_ORDER_4028);
    	insuranceEntity.setMainDataId(insuranceDto.getId());
    	insuranceEntity.setName(insuranceDto.getName());
    	insuranceEntity.setApiCode(insuranceDto.getApiCode());
    	insuranceEntity.setRationType(Assist.toString(insuranceDto.getRationType()));        	
    	insuranceEntity.setInsuranceCarriers(insuranceDto.getCompanyName());
    	
    	//保险报价
    	OfferReq offerReq = new OfferReq();
    	Offer offer = new Offer();
    	offer.setInsuranceId(insuranceEntity.getMainDataId());
    	offer.setRiskCode(null);
    	offer.setRationType(Assist.toInteger(insuranceEntity.getRationType()));
    	offer.setStarDate(DateUtil.fmtLocalDate(insuranceEntity.getBeginDate(), "yyyy-MM-dd"));
    	offer.setEndDate(DateUtil.fmtLocalDate(insuranceEntity.getEndDate(), "yyyy-MM-dd"));
    	offerReq.setData(offer);
    	offer.setPersonCount(Assist.toLong(Assist.add(handleReq.getAdultNum(), handleReq.getOldNum())));
    	offer.setChildCount(Assist.toLong(handleReq.getChildrenNum()));
    	try {
    		OfferDTO offerDto = iInsuranceService.acciQuotation(offerReq);
    		if (offerDto != null) {
    			insuranceEntity.setTotalAmount(offerDto.getPremium());
    		}
    	} catch (Exception e) {
    		throw new BusinessException(SystemError.CUSTOM_ORDER_4026);
    	}

    	//投保人
    	if (insuranceReq.getPolicyHolderIndex() != null) {
    		BusOrderTourist tourist = busOrderTouristList.get(insuranceReq.getPolicyHolderIndex());
    		if (tourist != null) {
    			insuranceEntity.setPolicyHolderId(tourist.getId());
    			insuranceEntity.setPolicyHolderName(Assist.join(tourist.getSurname(), tourist.getName()));
    		}
    	}

    	//受保人
    	if (Assist.isNotEmpty(insuranceTouristIndexList)) {
    		for (Integer touristIndex : insuranceTouristIndexList) {
    			if (touristIndex == null) continue;
    			BusOrderTourist tourist = busOrderTouristList.get(touristIndex);
    			if (tourist != null) {
    				tourist.setInsuranceId(insuranceEntity.getMainDataId());
    				tourist.setInsuranceName(insuranceEntity.getName());
    				tourist.setInsuranceStartDate(DateUtil.toLocalDateTime(insuranceEntity.getBeginDate()));
    				tourist.setInsuranceEndDate(DateUtil.toLocalDateTime(insuranceEntity.getEndDate()));
    				tourist.setInsuranceNumber(insuranceEntity.getInsuranceNumber());
//    				tourist.setInsurancePrice(null);
    			}
    		}
    	}
    	
        busOrderInsuranceMapper.insert(insuranceEntity);
        
        return insuranceEntity;
    }

    /**
     * 预订中心下单
     *
     * @param reqList 预订中心订单入参
     * @return 返回值
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Result payOrder(Long id,List<BusPayOrderCollectionReq> reqList, TokenUser user) {
    	BusOrderPayHandleReq handleReq = new BusOrderPayHandleReq();
    	handleReq.setUserId(user.getId());
    	handleReq.setOrderId(id);
    	handleReq.setSalesmanId(user.getId());
    	handleReq.setSalesmanName(user.getUsername());
    	return payOrderHandle(handleReq, reqList, false); 
    }
    
    /**
     * 支付
     */
    @Transactional
    @Override
    public Result<Long> payment(BusOrderPaymentReq req, TokenUser tokenUser) {
    	BusOrderPayHandleReq handleReq = toBean(req, BusOrderPayHandleReq.class);
    	handleReq.setUserId(tokenUser.getId());
    	handleReq.setSalesmanId(tokenUser.getId());
    	handleReq.setSalesmanName(tokenUser.getUsername());
    	
    	return payOrderHandle(handleReq, req.getCollectionReqList(), true); 
    }

    /**
     * B2C支付订单
     * @return
     */
    @Transactional
    @Override
    public Result<Long> payOrderB2C(BusOrderPayB2CReq req, Long userId) {
    	BusOrderPayHandleReq handleReq = toBean(req, BusOrderPayHandleReq.class);
    	
    	BusOrder busOrder = busOrderMapper.assertExistById(req.getOrderId());
    	
    	handleReq.setUserId(userId);
    	handleReq.setSalesmanId(busOrder.getSalesmanId());
    	handleReq.setSalesmanName(busOrder.getSalesmanName());
    	
    	//收款信息
    	BusPayOrderCollectionReq collectionReq = toBean(req, BusPayOrderCollectionReq.class);
    	collectionReq.setCollectionAmount(busOrder.getReceivableAmount());
    	collectionReq.setCurrencyId(BusConst.CURRENCY_ID_HKD);
    	collectionReq.setCurrency(BusConst.CURRENCY_NAME_HKD);
    	
    	return payOrderHandle(handleReq, Assist.asList(collectionReq), false);
    }
    
    /**
     * 支付订单逻辑处理
     * @param isOfflineSelf 是否线下自营渠道
     */
    private Result<Long> payOrderHandle(BusOrderPayHandleReq req, List<BusPayOrderCollectionReq> collectionReqList, boolean isOfflineSelf) {
    	validateArgs(req);
    	BusOrderPayHandleInfoDTO handleInfoDTO = new BusOrderPayHandleInfoDTO();
    	Long userId = req.getUserId();
    	LocalDateTime nowLocalDateTime = LocalDateTime.now();
        
        MainDataManualSystemDTO manualSystemDto = null;
        
        BusOrder busOrder = busOrderMapper.selectById(req.getOrderId());
        if(Objects.isNull(busOrder)){
            return Result.failed(SystemError.BUS_PRODUCT_9009);
        }
        BusProductDTO busProductDTO = busProductService.queryDetail(busOrder.getBusId());
        if(Objects.isNull(busProductDTO)){
            return Result.failed(SystemError.BUS_PRODUCT_9009);
        }
        BusProductReservationSettingsDTO reservationSettingsDTO = busProductDTO.getBusProductReservationSettingsDto();

        if (nowLocalDateTime.isAfter(busOrder.getPayExpireDate())) {
            // 支付超时
            throw new BusinessException(SystemError.BUS_ORDER_9009);
        }
//        busOrder.setPaymentStatus(1);
        busOrder.setModifiedId(userId);
        busOrder.setGmtModified(nowLocalDateTime);

        UserDTO userDTO = sysUserService.queryCacheUser(userId);
        
        //收款记录
        List<BusOrderCollection> busOrderCollectionList = EntityUtil.copyList(collectionReqList, BusOrderCollection.class);
        for (BusOrderCollection busOrderCollection : busOrderCollectionList) {
            // 获取对应汇率，计算支付金额
            MainDataCurrencyQueryDTO currencyQueryDTO = getExchangeRateById(busOrderCollection.getCurrencyId());
            BigDecimal marketExchangeRate = currencyQueryDTO.getMarketExchangeRate();
            BigDecimal amountHKD = busOrderCollection.getCollectionAmount().multiply(marketExchangeRate);;
            
            
            fillCreateEntityUserId(busOrderCollection, userId);
            String paymentNumber = generatorPaymentNumber(nowLocalDateTime);
            busOrderCollection.setOrderId(req.getOrderId());
            busOrderCollection.setCollectionNumber(paymentNumber);
            busOrderCollection.setCurrency(currencyQueryDTO.getCurrencyCode());
            busOrderCollection.setStandardAmount(amountHKD);//本位币金额
            busOrderCollection.setStatus(OrderCollectionStatus.UN_REJECT.getCode());
            busOrderCollection.setSalerId(req.getSalesmanId());
            busOrderCollection.setSalerName(req.getSalesmanName());
            busOrderCollection.setExchangeRate(marketExchangeRate);
        }
        
        //下单支付成功后，优惠相关处理
        payOrderHandleDiscounts(req, busOrder, userId, busOrderCollectionList, busProductDTO, handleInfoDTO);
        
        //总实收 = 实收金额 + 积分抵扣 + 优惠券 + 银联优惠
        BigDecimal amountCountHKD = BigDecimal.ZERO;
        for (BusOrderCollection collectionEntity : busOrderCollectionList) {
        	amountCountHKD = Assist.add(amountCountHKD, collectionEntity.getStandardAmount());
		}
        
        // 校验应收价格
        checkAmount(amountCountHKD, busOrder.getReceivableAmount());
        busOrder.setOfficialAmount(amountCountHKD);
        
        
        /** API产品下单调用接口  */
        if(ProductType.API_PRODUCT.getCode().equals(busProductDTO.getProductSource())){
        	//出票 - 中汽
            if(busProductDTO.getBusCompaniesId().equals(BusConst.COMPANIES_ID_RGL)){
            	outTicketRgl(busOrder);
            }else if(busProductDTO.getBusCompaniesId().equals(BusConst.COMPANIES_ID_HKT)){  //出票 - 中港通
            	outTicketHkt(busOrder);
            }
        }
        
        //外挂单
        if (ProductType.PLUG.getCode().equals(busOrder.getProductType())) {
        	BusManualOrder busManualOrder = busManualOrderMapper.assertExistSelectOneByKey("order_id", busOrder.getId());
        	notNull(busManualOrder.getSystemId(), SystemError.BUS_ORDER_9020);
        	
        	manualSystemDto = mainDataManualSystemService.findById(busManualOrder.getSystemId()).ok();
        	notNull(manualSystemDto, SystemError.MAINDATA_4026);
        }
        
//        /**
//         * 巴士下单成功后
//         * 1.减去使用的会员积分，增加消费的产生会员积分
//         * 2.减去使用的优惠券(机场快线无优惠券业务)
//         */
//        if (!useUnionpayDiscount) {
//            List<BusOrderCollection> airportExpressOrderCollectionThirdList = new ArrayList<>();
//            useAndUpdateCrmMemberPoints(busOrder, readyMoney, userId, airportExpressOrderCollectionThirdList);
//        }
        
        //是否需要二次确认
        boolean isConfirm = false;
        if (reservationSettingsDTO != null) {
        	isConfirm = BConst.ONE.equals(reservationSettingsDTO.getIsConfirm());
        }
        
        //新增收据记录
        insertReceipt(busOrder, userId, nowLocalDateTime, req.getSalesmanId());
        
        busOrder.setPaymentStatus(OrderPaymentStatus.ALREADY_PAYMENT.getCode());
        //立即确认
        if (!isConfirm) {
        	busOrder.setScheduledStatus(OrderScheduledStatus.RESERVE_SUCCESS.getCode());
        } else {  //二次确认
        	busOrder.setScheduledStatus(OrderScheduledStatus.CONFIRM_RESERVE.getCode());
		}

        //保存收款明细
        busOrderCollectionList.forEach(tourist -> {
            busOrderCollectionMapper.insert(tourist);
        });
        
        //旅客列表
        List<BusOrderTourist> touristList = busOrderTouristMapper.selectListByKey(BusOrderTourist::getOrderId, busOrder.getId());
        //订单成本列表
        Map<Integer, BusOrderCost> busOrderCostMap = busOrderCostMapper.queryTouristTypeMapByOrder(busOrder.getId());
        //保险信息
        BusOrderInsurance busOrderInsurance = busOrderInsuranceMapper.selectOneByKey("order_id", busOrder.getId());
        
        //下单支付成功后，对接供应商
        payOrderToSupplier(userId, busOrder, busProductDTO, touristList, busOrderCostMap, isConfirm, manualSystemDto, userDTO);
        
        //下单支付成功后，对接财务中心
        payOrderToFinance(busOrder, busOrderCollectionList, userId, busProductDTO, req, handleInfoDTO);
        
        //下单支付成功后，对接保险
        payOrderToInsurance(busOrder, touristList, userId, busOrderInsurance);
        
        busOrderMapper.updateById(busOrder);
        return Result.success(req.getOrderId());
    }
    
    /**
     * 出票 - 中汽
     */
    private void outTicketRgl(BusOrder busOrder) {
    	//中汽巴士下单接口
        Map<String, Object> placeOrderMap = new HashMap<>();
        placeOrderMap.put("orderNo", busOrder.getThirdTicketNo());//销售单号
        try{
            RlgOrderUtil.outTicket(placeOrderMap);
        }catch (Exception e){
        	getLogger().error("中汽巴士接口出票异常 [orderId : {}]", busOrder.getId(), e);
            throw new BusinessException(SystemError.BUS_ORDER_9017);
        }
	}
    
    /**
     * 出票 - 中港通
     */
    private void outTicketHkt(BusOrder busOrder) {
    	//中港通巴士下单
        Map<String,String> paramMap = new HashMap<>();
        paramMap.put("OrderNo",busOrder.getThirdTicketNo());
        paramMap.put("traceNo",String.valueOf(busOrder.getId()));
        Map<String,Object> resultMap = null;
        try{
            resultMap = HktOrderUtil.getTickets(paramMap);
            if (resultMap == null) {
            	throw new CtsException("中港通出票，结果为空");
            }
            Map getTicketsMap = (Map)resultMap.get("getTickets");
            if (getTicketsMap == null) {
            	throw new CtsException("中港通出票，结果为空");
            }
            if (!"SUCCESS".equals(getTicketsMap.get("errorCode"))) {
            	throw new CtsException("中港通出票失败");
            }
        }catch (Exception e){
        	getLogger().error("中港通巴士接口出票异常 [orderId : {}] [result : {}]", busOrder.getId(), toJson(resultMap), e);
            throw new BusinessException(SystemError.BUS_ORDER_9017);
        }
	}
    
    /**
     * 取消订单
     * @param cancelOrderReq
     * @param user
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Result cancelOrder(BusCancelOrderReq req, TokenUser user) {
    	BusOrderCancelHandleReq handleReq = toBean(req, BusOrderCancelHandleReq.class);
    	handleReq.setSalesmanId(user.getId());
    	handleReq.setSalesmanName(user.getUsername());
    	return cancelOrderHandle(handleReq, req.getBusOrderRefundCancelReqList(), getTokenUserId(user));
    }
    
    /**
     * B2C取消订单
     * @param req
     * @return
     */
    @Transactional
    @Override
    public Result<Void> cancelOrderB2C(BusOrderCancelB2CReq req, Long userId) {
    	validateArgs(req);
    	BusOrderCancelHandleReq handleReq = toBean(req, BusOrderCancelHandleReq.class);
    	
    	
    	BusOrderCollection busOrderCollection = Assist.findFirst(busOrderCollectionMapper.selectListByKey("order_id", req.getOrderId()));
    	notNull(busOrderCollection, SystemError.CUSTOM_ORDER_4047);
    	
    	BusOrderRefundCancelReq cancelReq = new BusOrderRefundCancelReq();
    	cancelReq.setRefundAmount(busOrderCollection.getCollectionAmount());
    	cancelReq.setRefundWayId(busOrderCollection.getCollectionWayId());
    	cancelReq.setRefundWay(busOrderCollection.getCollectionWay());
    	cancelReq.setRefundAccount(busOrderCollection.getPayer());
    	cancelReq.setCurrencyId(busOrderCollection.getCurrencyId());
    	cancelReq.setCurrency(busOrderCollection.getCurrency());
    	handleReq.setSalesmanId(busOrderCollection.getSalerId());
    	handleReq.setSalesmanName(busOrderCollection.getSalerName());
    	
    	return cancelOrderHandle(handleReq, Assist.asList(cancelReq), userId);
    }
    
    /**
     * 取消订单逻辑处理
     * @param req
     * @param userId
     * @return
     */
    private Result<Void> cancelOrderHandle(BusOrderCancelHandleReq req, List<BusOrderRefundCancelReq> cancelReqList, Long userId) {
    	BusOrder busOrder = busOrderMapper.selectById(req.getOrderId());
        if (busOrder == null) {
            throw new BusinessException(SystemError.BUS_PRODUCT_9009);
        }


        LocalDateTime nowLocalDateTime = LocalDateTime.now();

        if (busOrder.getPaymentStatus() == OrderPaymentStatus.UN_PAYMENT.getCode()) {
            //未付款，取消订单
            busOrder.setPaymentStatus(OrderPaymentStatus.ALREADY_CANCEL.getCode());
            
            //回滚已售座位数
        	int touristNum = busOrderTouristMapper.selectCountByKey("order_id", busOrder.getId());
        	if (touristNum > 0) {
        		busProductService.rollbackSold(busOrder.getBusId(), touristNum, busOrder.getEffectiveTime(), userId);
        	}
        } else if (busOrder.getPaymentStatus() == OrderPaymentStatus.ALREADY_PAYMENT.getCode()) {
            // 已付款,取消订单
            if (!(busOrder.getCancelStatus() == null || ApprovalStatus.REVIEW_NO.getCode().equals(busOrder.getCancelStatus()))) {               
            	//正在取消订单，请勿重复提交
                throw new BusinessException(SystemError.AIREXPRESS_ORDER_60023);
            }
            if (com.baomidou.mybatisplus.core.toolkit.CollectionUtils.isEmpty(cancelReqList)) {
                // 退款记录不能为空
                throw new BusinessException(SystemError.AIREXPRESS_ORDER_60005);
            }
            
            //删除上一次的取消记录明细
            busOrderRefundMapper.deleteByKey("order_id", busOrder.getId());
            
            busOrder.setCancelStatus(ApprovalStatus.REVIEWING.getCode());
            List<BusOrderRefund> busOrderRefundList = EntityUtil.copyList(cancelReqList, BusOrderRefund.class);
            for (BusOrderRefund busOrderRefund : busOrderRefundList) {
                // 获取对应汇率，计算支付金额
                MainDataCurrencyQueryDTO currencyQueryDTO = getExchangeRateById(busOrderRefund.getCurrencyId());
                BigDecimal marketExchangeRate = currencyQueryDTO.getMarketExchangeRate();
                BigDecimal refundAmountHKD = busOrderRefund.getRefundAmount().multiply(marketExchangeRate);
                busOrderRefund.setRefundNumber(OperateNumberGenerateUtil.generateRefundNumber(nowLocalDateTime));
                busOrderRefund.setOrderId(req.getOrderId());
                busOrderRefund.setCurrency(currencyQueryDTO.getCurrencyCode());
                busOrderRefund.setStandardAmount(refundAmountHKD);//本位币金额
                busOrderRefund.setStatus(OrderRefundStatus.AUDITING.getCode());
                busOrderRefund.setRefundReason(req.getRefundReason());
                busOrderRefund.setRemark(req.getRemark());
                busOrderRefund.setIsDeleted(IsDeletedCode.NO.getCode());
                busOrderRefund.setExchangeRate(marketExchangeRate);
            }


            BusProductDTO busProductDTO = busProductService.queryDetail(busOrder.getBusId());
            if (Objects.isNull(busProductDTO)) {
                return Result.failed(SystemError.BUS_PRODUCT_9009);
            }

//            /**
//             * do something 退积分，退优惠码(机场快线无优惠码)，退银联优惠
//             */
//            if (busOrder.getUsingPoints() != null && busOrder.getUsingPoints() > 0) {
//                BigDecimal crmExchangeRateCNY = getCrmExchangeRateByName("CNY");
//                ContactQueryDTO contactQuery;
//                try {
//                    CrmMemberQueryReq crmMemberQueryReq = new CrmMemberQueryReq(busOrder.getMemberQueryType(), busOrder.getMemberQueryCode(), busOrder.getMemberQueryCertificatesType().toString());
//                    contactQuery = crmMemberService.queryMember(crmMemberQueryReq);
//                    // 构建创建用户ID，人民币金额，回退积分点数
//                    String crmUserId = String.valueOf(userId).substring(0, 12);
//                    BigDecimal rmbAmount = busOrder.getReceivableAmount().divide(crmExchangeRateCNY, 2, BigDecimal.ROUND_HALF_UP);
//
//                    CrmMemberUpdatePointsReq crmMemberUpdatePointsReq = new CrmMemberUpdatePointsReq();
//                    crmMemberUpdatePointsReq.setUpdateType(2);
//                    crmMemberUpdatePointsReq.setNumPoints(new BigDecimal(busOrder.getUsingPoints()));//do积分点数
//                    crmMemberUpdatePointsReq.setXCtsProdDesc("單項委託-火车巴士船票(机场快线)");//do板塊產品描述 (建議使用: 集團產品名稱 + “ – “ + 板塊產品名稱, 例如: 港澳参团游 - 主题游)")
//                    crmMemberUpdatePointsReq.setTxnNum(busOrder.getOrderNumber() + "-3");//do交易編號 (如為旅行團交易, 目前我們的格式是 旅行團交易編號 + ‘-‘ + 序號, 例如: 01P08192131025A155506-1
//                    crmMemberUpdatePointsReq.setAmtVal(busOrder.getReceivableAmount());
//                    crmMemberUpdatePointsReq.setXCtsRmbAmount(rmbAmount);
//                    crmMemberUpdatePointsReq.setCreateUserid(crmUserId);
//                    crmMemberUpdatePointsReq.setXCtsTxnOrgCode("219910000010");
//                    crmMemberUpdatePointsReq.setTxnChannelCd("16");
//                    crmMemberUpdatePointsReq.setXCtsTxnChnNum("211099000010");
//                    crmMemberUpdatePointsReq.setProdName("8821090000");
//                    crmMemberUpdatePointsReq.setXCtsProdCode("8821090300");
//                    crmMemberService.updatePoints(crmMemberUpdatePointsReq, contactQuery);
//                } catch (Exception e) {
//                    if (e instanceof BusinessException) {
//                        throw e;
//                    } else {
//                        throw new BusinessException(SystemError.AIREXPRESS_ORDER_60009);
//                    }
//                }
//            } else {
//                /**
//                 * 扣减银联优惠
//                 */
//                QueryWrapper<BusOrderCollection> collectionQueryWrapper = new QueryWrapper<>();
//                collectionQueryWrapper.lambda().eq(BusOrderCollection::getOrderId, busOrder.getId());
//                collectionQueryWrapper.lambda().eq(BusOrderCollection::getIsDeleted, IsDeletedCode.NO);
//                List<BusOrderCollection> busOrderCollectionList = busOrderCollectionMapper.selectList(collectionQueryWrapper);
//                if (com.baomidou.mybatisplus.core.toolkit.CollectionUtils.isNotEmpty(busOrderCollectionList)) {
//                    BusOrderCollection busOrderCollectionBank = null;
//                    String payer = null;
//                    for (BusOrderCollection busOrderCollection : busOrderCollectionList) {
//                    	if (busOrderCollection.getCollectionWayId() != null) {
//                    		if (busOrderCollection.getCollectionWayId() == 1372458875539845121L) {//1372458875539845121 銀行優惠
//                    			busOrderCollectionBank = busOrderCollection;
//                    		}
//                    		if (busOrderCollection.getCollectionWayId() == 1372449873087078401L || busOrderCollection.getCollectionWayId() == 1372467581262393346L) {//信用卡,银行卡
//                    			payer = busOrderCollection.getPayer();
//                    		}
//                    	}
//                    }
//                    if (busOrderCollectionBank != null) {
//                        OperateBankRefundReq deductReq = new OperateBankRefundReq();
//                        deductReq.setId(busOrderCollectionBank.getUnionpayDiscountId());//银联优惠ID
//                        deductReq.setRefundTotalPaidIn(busOrderCollectionBank.getStandardAmount());//本位币金额
//                        deductReq.setCardNumber(payer);//卡号
//                        deductReq.setBusinessType(SystemBusinessType.AIR_EXPRESS.getCode());
//                        deductReq.setRelationId(busOrder.getBusId());//产品ID
//                        deductReq.setChannelId(OrderSource.CPM.getCode().longValue());//订单来源
//                        Result deductResult = operateBankPreferenceService.refundUpdate(deductReq, new TokenUser() {{
//                        	setId(userId);
//                        }});
//                        if (!deductResult.isSuccess()) {
//                            // 校验银行优惠不满足条件
//                            SystemError defined = SystemError.getDefined(deductResult.getCode());
//                            throw new BusinessException(defined);
//                        }
//                    }
//                }
//            }
            /**
             * 审批电子流
             */
            log.info("【机场快线订单】submit cancel order approval, business type:{}, approval type:{}", SystemBusinessType.AIR_EXPRESS, SysApprovalType.CANCEL_BUS);
            sysApprovalService.start(SystemBusinessType.BUS_TICKET.getCode(), SysApprovalType.CANCEL_BUS.getCode(), busOrder.getId(), req.getSalesmanId(), null, null).ok();
            
            //保存收款明细
            busOrderRefundList.forEach(tourist -> {
                tourist.setCreateId(userId);
                tourist.setGmtCreate(nowLocalDateTime);
                busOrderRefundMapper.insert(tourist);
            });
        }

        busOrder.setModifiedId(userId);
        busOrder.setGmtModified(nowLocalDateTime);
        busOrderMapper.updateById(busOrder);
        
        return newResult();
    }

        /**
         * 获取银联优惠金额
         *
         * @param busOrder
         * @param collection
         * @param user
         * @return
         */
        private void useAmountByBankReference(BusOrder busOrder, BusOrderCollection collection, Long userId) {
            OperateBankConformQueryReq operateBankConformQueryReq = new OperateBankConformQueryReq();
            operateBankConformQueryReq.setId(collection.getUnionpayDiscountId());//银联优惠ID
            operateBankConformQueryReq.setCardNumber(collection.getPayer());//卡号
            operateBankConformQueryReq.setTotalPaidIn(busOrder.getOrderAmount());//订单金额
            operateBankConformQueryReq.setBusinessType(SystemBusinessType.AIR_EXPRESS.getCode());
            operateBankConformQueryReq.setRelationId(busOrder.getBusId());//产品ID
            operateBankConformQueryReq.setChannelId(OrderSource.CPM.getCode().longValue());//订单来源
            operateBankConformQueryReq.setUserId(userId);
            Result<OperateBankPreferenceQueryDTO> operateBankPreferenceQueryDTOResult = operateBankPreferenceService.queryConform(operateBankConformQueryReq);
            if (!operateBankPreferenceQueryDTOResult.isSuccess()) {
                // 校验银行优惠不满足条件
                SystemError defined = SystemError.getDefined(operateBankPreferenceQueryDTOResult.getCode());
                throw new BusinessException(defined);
            }
            OperateBankPreferenceQueryDTO bankQueryDto = operateBankPreferenceQueryDTOResult.getData();
            if (bankQueryDto.getDiscountType() == 1) {
                // 使用满额折扣优惠
                // 校验应收价格是否符合满减优惠
                if (busOrder.getReceivableAmount().compareTo(bankQueryDto.getFullAmount()) == -1) {
                    // 校验银行优惠不满足条件
                    throw new BusinessException(SystemError.AIREXPRESS_ORDER_60018);
                }
                collection.setCollectionAmount(bankQueryDto.getReductionAmount());
            } else {
                // 使用百分比优惠
                BigDecimal currentAmount = busOrder.getReceivableAmount().multiply(new BigDecimal(String.valueOf(bankQueryDto.getDiscountPercent())));
                currentAmount = currentAmount.compareTo(bankQueryDto.getMaxDiscount()) > 0 ? bankQueryDto.getMaxDiscount() : currentAmount;
                collection.setCollectionAmount(currentAmount);
            }
            /**
             * 扣减银联优惠
             */
            OperateBankDeductReq deductReq = new OperateBankDeductReq();
            deductReq.setId(collection.getUnionpayDiscountId());//银联优惠ID
            deductReq.setCardNumber(collection.getPayer());//卡号
            deductReq.setTotalPaidIn(busOrder.getOrderAmount());//订单金额
            deductReq.setBusinessType(SystemBusinessType.AIR_EXPRESS.getCode());
            deductReq.setRelationId(busOrder.getBusId());//产品ID
            deductReq.setChannelId(OrderSource.CPM.getCode().longValue());//订单来源
//            deductReq.setUserId(user.getId());
            Result deductResult = operateBankPreferenceService.deduct(deductReq, new TokenUser() {{
            	setId(userId);
            }});
            if (!deductResult.isSuccess()) {
                // 校验银行优惠不满足条件
                SystemError defined = SystemError.getDefined(deductResult.getCode());
                throw new BusinessException(defined);
            }
        }


    /**
     * 校验积分是否充足
     *
     * @param busOrder
     * @param usingPoints
     */
    private void checkMemberPoints(BusOrder busOrder, BigDecimal usingPoints) {
        ContactQueryDTO contactQuery;
        try {
            CrmMemberQueryReq crmMemberQueryReq = new CrmMemberQueryReq(1, busOrder.getMemberId(), null);
            contactQuery = crmMemberService.queryMember(crmMemberQueryReq);
        } catch (Exception e) {
            if (e instanceof BusinessException) {
                throw e;
            } else {
                throw new BusinessException(SystemError.AIREXPRESS_ORDER_60009);
            }
        }
        BigDecimal findMemberPoints = new BigDecimal(String.valueOf(contactQuery.getMember().getPoint1Value()));
        if (findMemberPoints.compareTo(usingPoints) < 0) {
            // 会员积分不足
            throw new BusinessException(SystemError.AIREXPRESS_ORDER_60008);
        }
    }


    /**
     * 根据币种ID获取汇率，获取汇率,
     *
     * @return
     */
    private MainDataCurrencyQueryDTO getExchangeRateById(Long currencyId) {
        MainDataCurrencyUpdateStatusReq mainDataCurrencyUpdateStatusReq = new MainDataCurrencyUpdateStatusReq();
        mainDataCurrencyUpdateStatusReq.setId(currencyId);
        Result<MainDataCurrencyQueryDTO> queryCurrencyRateResult = mainDataCurrencyService.query(mainDataCurrencyUpdateStatusReq);
        if (!queryCurrencyRateResult.isSuccess()) {
            SystemError defined = SystemError.getDefined(queryCurrencyRateResult.getCode());
            throw new BusinessException(defined);
        }
        return queryCurrencyRateResult.getData();
    }



    /**
     * 订单中心-巴士票订单分页查询列表
     * @param req
     * @return
     */
    @Override
    public PageResponse<BusOrderPageDTO> queyList(BusOrderPageReq req, TokenUser tokenUser) {
    	//临时做法，默认填充菜单ID
    	if (req.getMenuId() == null) {
    		req.setMenuId(36130784662257664l);
    	}
    	//数据权限
    	List<Long> permissionUserList = sysPermissionService.queryPermission(req.getMenuId(), getTokenUserId(tokenUser)).ok();
    	
        IPage<BusOrderPageDTO> agentPage = new Page<>(req.getPageNo(),req.getPageSize());
        agentPage = busOrderMapper.queryList(req, permissionUserList);
        List<BusOrderPageDTO> busOrderPageDTOList = agentPage.getRecords();
        if(!CollectionUtils.isEmpty(busOrderPageDTOList)){
            for(BusOrderPageDTO busOrderPageDTO : busOrderPageDTOList){
                //根据线路id查询线路信息
                BusLineDTO busLineDTO = busLineService.queryByLineId(busOrderPageDTO.getLineId());
                if(!Objects.isNull(busLineDTO)){
                    busOrderPageDTO.setVehicleType(busLineDTO.getVehicleType());
                    busOrderPageDTO.setGatewayName(busLineDTO.getGatewayName());
                }
                
                //外挂单
                if (ProductType.PLUG.getCode().equals(busOrderPageDTO.getProductType())) {
                	BusManualOrder busManualOrder = busManualOrderMapper.selectOneByKey("order_id", busOrderPageDTO.getId());
                	if (busManualOrder != null) {
                		busOrderPageDTO.setManualTicketMode(busManualOrder.getTicketMode());;
                	}
                }
            }
        }
        PageResponse<BusOrderPageDTO> result = new PageResponse<>(agentPage.getRecords(),agentPage.getCurrent() == 1,
                agentPage.getTotal() <= (agentPage.getCurrent() * agentPage.getSize()),
                agentPage.getTotal(), agentPage.getCurrent(), agentPage.getSize());
        return result;
    }

    /**
     * 根据订单id查询订单详细信息
     *
     * @param orderId 订单id
     * @return 订单消息
     */
    @Override
    public Result<BusOrderDetailDTO> queryOrderDetailInfo(Long orderId) {
        //根据订单id查询订单信息
        BusOrder busOrder = busOrderMapper.selectById(orderId);
        if(Objects.isNull(busOrder)){
            return Result.failed(SystemError.BUS_ORDER_9005);
        }
        BusOrderDetailDTO busOrderDetailDTO =  EntityUtil.copy(busOrder,BusOrderDetailDTO.class);
        
        //订单状态
        if (busOrderDetailDTO.getPaymentStatus() == null || OrderPaymentStatus.UN_PAYMENT.getCode().equals(busOrderDetailDTO.getPaymentStatus())) {
        	busOrderDetailDTO.setOrderStatus(OrderStatus.UN_PAYMENT.getCode());
        } else if (OrderPaymentStatus.ALREADY_CANCEL.getCode().equals(busOrderDetailDTO.getPaymentStatus())) {
			busOrderDetailDTO.setOrderStatus(OrderStatus.ALREADY_CANCEL.getCode());
		} else if (busOrderDetailDTO.getScheduledStatus() == null || OrderScheduledStatus.CONFIRM_RESERVE.getCode().equals(busOrderDetailDTO.getScheduledStatus())) {
        	busOrderDetailDTO.setOrderStatus(OrderStatus.CONFIRM_RESERVE.getCode());
		} else if (OrderScheduledStatus.RESERVE_SUCCESS.getCode().equals(busOrderDetailDTO.getScheduledStatus())) {
			busOrderDetailDTO.setOrderStatus(OrderStatus.RESERVE_SUCCESS.getCode());
		} else if (OrderScheduledStatus.RESERVE_FAIL.getCode().equals(busOrderDetailDTO.getScheduledStatus())) {
			busOrderDetailDTO.setOrderStatus(OrderStatus.RESERVE_FAIL.getCode());
		}
        
        //巴士外挂单
        BusManualOrder busManualOrder = busManualOrderMapper.selectOne(new QueryWrapper<BusManualOrder>().lambda().eq(BusManualOrder::getOrderId, orderId));
        if(!Objects.isNull(busManualOrder)){
            BusManualOrderDetailDTO busManualOrderDetailDTO =  EntityUtil.copy(busManualOrder,BusManualOrderDetailDTO.class);
            busOrderDetailDTO.setBusManualOrderDetailDTO(busManualOrderDetailDTO);
            busOrderDetailDTO.setManualTicketMode(busManualOrder.getTicketMode());;
        }


        //巴士收款明细信息
        List<BusOrderCollection> busOrderCollectionList = busOrderCollectionMapper.selectList(new QueryWrapper<BusOrderCollection>().lambda().eq(BusOrderCollection::getOrderId, orderId));
//        if(!CollectionUtils.isEmpty(busOrderCollectionList)){
//            List<BusOrderCollectionDTO> busOrderCollectionDTOList =  EntityUtil.copyList(busOrderCollectionList,BusOrderCollectionDTO.class);
//            busOrderDetailDTO.setBusOrderCollectionDTOList(busOrderCollectionDTOList);
//        }
        
        //巴士订单旅客信息
        List<BusOrderTourist> busOrderTouristList = busOrderTouristMapper.selectList(new QueryWrapper<BusOrderTourist>().lambda().eq(BusOrderTourist::getOrderId, orderId));
        if(!CollectionUtils.isEmpty(busOrderTouristList)){
        	List<BusOrderTouristDTO> busOrderTouristDTOList =  EntityUtil.copyList(busOrderTouristList,BusOrderTouristDTO.class);
//        	busOrderDetailDTO.setBusOrderTouristDTOList(busOrderTouristDTOList);
        	
        	//总收款费用
        	BigDecimal collectionAmount = Assist.sumBigDecimal(busOrderCollectionList, BusOrderCollection::getCollectionAmount);
        	//旅客票价 = 总收款费用 / 旅客人数 
        	BigDecimal touristAmount = Assist.divide(collectionAmount, busOrderTouristDTOList.size());
        	Assist.forEach(busOrderTouristDTOList, dto -> dto.setBusPrice(touristAmount));
        	//拼接座位号
        	String touristSeatNumbers = Assist.join(busOrderTouristDTOList, BusOrderTouristDTO::getSeatsNumber);
        	busOrderDetailDTO.setTouristSeatNumbers(touristSeatNumbers);       	
        }        
        

//        //巴士退款明细信息
//        List<BusOrderRefund> busOrderRefundList = busOrderRefundMapper.selectList(new QueryWrapper<BusOrderRefund>().lambda().eq(BusOrderRefund::getOrderId, orderId));
//        if(!CollectionUtils.isEmpty(busOrderRefundList)){
//            List<BusOrderRefundDTO> busOrderRefundDTOList =  EntityUtil.copyList(busOrderRefundList,BusOrderRefundDTO.class);
//            busOrderDetailDTO.setBusOrderRefundDTOList(busOrderRefundDTOList);
//        }
        
        //巴士信息
        BusProductDTO busProductDTO = busProductService.queryDetail(busOrder.getBusId());
        if(busProductDTO != null){
        	busOrderDetailDTO.setVehicleType(busProductDTO.getVehicleType());
        	busOrderDetailDTO.setGatewayName(busProductDTO.getGatewayName());        	
        	
        	//巴士产品预订设置
        	BusProductReservationSettingsDTO busProductReservationSettingsDTO = busProductDTO.getBusProductReservationSettingsDto();
        	if (busProductReservationSettingsDTO != null) {
        		busOrderDetailDTO.setBookingInformation(busProductReservationSettingsDTO.getBookingInformation());
        		busOrderDetailDTO.setTicketCollectionType(busProductReservationSettingsDTO.getTicketCollectionType());
        		busOrderDetailDTO.setTicketCollection(busProductReservationSettingsDTO.getTicketCollection());
        		busOrderDetailDTO.setExchangeMethod(busProductReservationSettingsDTO.getExchangeMethod());
        	}
        }
        
        if (busOrder.getLineId() != null) {
        	BusLineDTO busLineDTO = busLineService.queryDetail(busOrder.getLineId());
        	if (busLineDTO != null) {
        		busOrderDetailDTO.setVehicleType(busLineDTO.getVehicleType());
        		busOrderDetailDTO.setGatewayName(busLineDTO.getGatewayName());;
        	}
        }

        return Result.success(busOrderDetailDTO);
    }

    /**
     * 修改旅客信息
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result updateBusOrderTourist(BusOrderTouristReq touristReq, Long userId) {

        BusOrderTourist busOrderTourist = busOrderTouristMapper.selectById(touristReq.getId());
        if(Objects.isNull(busOrderTourist)){
            return Result.failed(SystemError.BUS_ORDER_9006);
        }
        busOrderTourist =  EntityUtil.copy(touristReq,BusOrderTourist.class);
        busOrderTourist.setModifiedId(userId);
        busOrderTourist.setGmtModified(LocalDateTime.now());
        busOrderTouristMapper.updateById(busOrderTourist);
        return Result.success();
    }


    /**
     * 确认退款
     *
     * @param id
     * @param refundId
     * @param userId
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Result confirmRefund(Long id, Long refundId, Long userId) {

        BusOrder busOrder = busOrderMapper.selectById(id);
        if (busOrder == null) {
            //订单不存在
            throw new BusinessException(SystemError.BUS_PRODUCT_9009);
        }
        if (!(busOrder.getCancelStatus() == ApprovalStatus.REVIEW_YES.getCode())) {
            //审批成功状态的订单，才可以做确认退款操作
            throw new BusinessException(SystemError.BUS_ORDER_9013);
        }
        QueryWrapper<BusOrderRefund> busOrderRefundQueryWrapper = new QueryWrapper<>();
        busOrderRefundQueryWrapper.lambda().eq(BusOrderRefund::getOrderId, id);
        List<BusOrderRefund> busOrderRefundList = busOrderRefundMapper.selectList(busOrderRefundQueryWrapper);
        boolean ifAllRefund = true;
        for (BusOrderRefund busOrderRefund : busOrderRefundList) {
            if (refundId.equals(busOrderRefund.getId())) {
                // 确认退款
                busOrderRefund.setStatus(OrderRefundStatus.REFUND_SUCCESSFUL.getCode());
                busOrderRefundMapper.updateById(busOrderRefund);
                
                //确认退款对接财务中心
                confirmRefundToFinance(busOrderRefund, userId);
            }
            /**
             * do something暂无支付方式主数据，5-银行优惠，会员积分，优惠券，
             * 除5以外的支付方式记录的状态，有一个不是退款成功，ifAllRefund为false
             */
            if (!(busOrderRefund.getRefundWayId() == 5) && !(busOrderRefund.getStatus() == OrderRefundStatus.REFUND_SUCCESSFUL.getCode())) {
                ifAllRefund = false;
            }
        }
        if (ifAllRefund) {
            // 全部已退款,更新状态
            busOrder.setCancelStatus(ApprovalStatus.REFUND_SUCCESS.getCode());
            busOrderMapper.updateById(busOrder);
        }
        return Result.success();
    }
    
    /**
     * 支付页面查询信息
     * @param id
     * @return
     */
    @Override
    public Result<BusOrderPayInfoDTO> paymentInfoById(Long id) {
        BusOrder busOrder = busOrderMapper.selectById(id);
        BusOrderPayInfoDTO busOrderPayInfoDTO =  EntityUtil.copy(busOrder,BusOrderPayInfoDTO.class);
        
        //积分
        if (busOrder.getUsingPoints() != null) {

        }

        //推广码
        if (Assist.isNotBlank(busOrder.getCouponNumber())) {
        	OperatePromotionQueryDTO promotionDTO = findPromotionCode(busOrder);
        	
        	busOrderPayInfoDTO.setReceivableAmount(Assist.subtract(busOrderPayInfoDTO.getReceivableAmount(), promotionDTO.getReductionAmount()));;
        	
        	busOrderPayInfoDTO.setCouponNumber(promotionDTO.getActivityCode());
        	busOrderPayInfoDTO.setCouponNumberAmount(promotionDTO.getReductionAmount());
        	busOrderPayInfoDTO.setCouponNumberName(promotionDTO.getName());
        }
        
        return Result.success(busOrderPayInfoDTO);
    }

    /**
     * 查询订单的旅客信息列表
     * @param req
     * @return
     */
    @Override
    public Result<PageResponse<BusOrderTouristDTO>> queryTouristListByOrder(OperationPageByIdReq req) {
    	IPage<BusOrderTouristDTO> page = busOrderTouristMapper.selectPageByKeyDesc(BusOrderTouristDTO.class, req, "order_id", req.getId(), "gmt_create");
    	return newPageResult(page);
    }
    
    /**
     * 查询订单的收款明细信息列表
     * @param req
     * @return
     */
    @Override
    public Result<PageResponse<BusOrderCollectionDTO>> queryCollectionListByOrder(OperationPageByIdReq req) {
    	IPage<BusOrderCollectionDTO> page = busOrderCollectionMapper.selectPageByKeyDesc(BusOrderCollectionDTO.class, req, "order_id", req.getId(), "gmt_create");
    	return newPageResult(page);
    }

    /**
     * 查询订单的退款记录信息列表
     * @param req
     * @return
     */
    @Override
    public Result<PageResponse<BusOrderRefundDTO>> queryRefundListByOrder(OperationPageByIdReq req) {
    	IPage<BusOrderRefundDTO> page = busOrderRefundMapper.selectPageByKeyDesc(BusOrderRefundDTO.class, req, "order_id", req.getId(), "gmt_create");
    	return newPageResult(page);
    }
    
    /**
     * 确认巴士订单
     * @param req
     * @return
     */
    @Transactional
    @Override
    public Result<Void> confirmBusOrder(BusBusOrderConfirmReq req, TokenUser tokenUser) {
    	BusOrder busOrder = busOrderMapper.assertExistById(req.getId());
    	
    	//订单更新为预订成功
    	BusRefreshByConfirmOrderReq busRefreshByConfirmOrderReq = new BusRefreshByConfirmOrderReq();
    	busRefreshByConfirmOrderReq.setId(req.getId());
    	busRefreshByConfirmOrderReq.setScheduledStatus(OrderScheduledStatus.RESERVE_SUCCESS.getCode());
    	refreshByConfirmOrder(busRefreshByConfirmOrderReq, tokenUser).ok();
    	
    	//调用供应商接口
    	SupplierOrderSystemFreeCallConfirmReq callReq = toBean(req, SupplierOrderSystemFreeCallConfirmReq.class);
    	callReq.setSaleNumber(busOrder.getOrderNumber());
    	supplierOrderService.freeCallSystemConfirm(callReq, getTokenUserId(tokenUser));
    	return newResult();
    }
    
    /**
     * 查询订单的可退金额
     * @param req
     * @return
     */
    @Override
    public Result<BigDecimal> findCanRefundAmountByOrder(OperationByIdReq req) {
    	BigDecimal amount = BigDecimal.ZERO;
    	//收款记录
    	List<BusOrderCollection> list = busOrderCollectionMapper.selectListByKey("order_id", req.getId());
    	for (BusOrderCollection entity : list) {
    		//推广码、银联优惠、积分不累加到可退金额
    		if (BusConst.PAY_WAY_ID_PROMOTION_CODE.equals(entity.getCollectionWayId())
    				|| BusConst.PAY_WAY_ID_BANK_DISCOUNTS.equals(entity.getCollectionWayId())
    				|| BusConst.PAY_WAY_ID_INTEGRAL.equals(entity.getCollectionWayId())) {
    			continue;
    		}

    		amount = Assist.add(amount, entity.getStandardAmount());
    	}
    	
    	//订单
    	BusOrder busOrder = busOrderMapper.assertExistById(req.getId());
    	
    	//扣除手续费
    	amount = busProductReservationSettingsService.calcRefundFee(busOrder.getBusId(), amount);
    	
    	return newResult(amount);
    }
    
    /**
     * 确认订单后的相关巴士处理
     * @param req
     * @return
     */
    @Transactional
    @Override
    public Result<Void> refreshByConfirmOrder(BusRefreshByConfirmOrderReq req, TokenUser tokenUser) {
    	validateArgs(req);
    	
    	BusOrder entity = newUpdateEntity(BusOrder.class, req, tokenUser);
    	busOrderMapper.assertUpdateById(entity);    	
    	
    	return newResult();
    }

    @Override
    public Integer findBusProduct7DaySaleCount(Long id) {
        return baseMapper.selectSaleCount(id);
    }
    
    /**
     * 获取退款记录(财务-内部接口)
     *
     * @param orderNumber 订单编号
     * @return
     */
    @Override
    public List<OrderRefundDTO> getRefundList(String orderNumber) {
    	validateNotBlank(orderNumber);
    	
    	BusOrder orderEntity = busOrderMapper.assertExistSelectOneByKey("order_number", orderNumber);
    	
    	List<OrderRefundDTO> dtoList = new ArrayList<>();
    	List<BusOrderRefund> list = busOrderRefundMapper.selectListByKey("order_id", orderEntity.getId());
    	if (Assist.isNotEmpty(list)) {
    		for (BusOrderRefund entity : list) {
    			OrderRefundDTO dto = new OrderRefundDTO();
    			dto.setBusinessType(SystemBusinessType.BUS_TICKET.getCode());
                dto.setRefundId(orderEntity.getId());
                dto.setRefundNumber(orderEntity.getOrderNumber());
                dto.setRefundReason(entity.getRefundReason());
                dto.setRemark(entity.getRemark());
                dto.setRefundType(entity.getRefundWay());
                dto.setTotalReceivables(orderEntity.getReceivableAmount());
                dto.setPaidInAmount(orderEntity.getReceivableAmount());
                dto.setRefundAmount(entity.getRefundAmount());
                dto.setApprovalAmount(entity.getRefundAmount()); //审批退款金额
                dto.setCurrency(entity.getCurrency());
    			
    			dtoList.add(dto);
			}
    	}
    	
    	return dtoList;
    }
    
    /**
     * 巴士订单通知旅客
     * @param req
     * @return
     */
    @Override
    public Result<Void> informTourist(BusOrderOrderInformTouristReq req) {
    	BusOrder busOrder = busOrderMapper.assertExistById(req.getOrderId());
    	
    	//邮箱
    	if (BConst.ONE.equals(req.getInformType())) {
    		
    	} else if (BConst.TWO.equals(req.getInformType())) {  //短信
//    		validateNotNull(req.getPhone());
//    		HashMap<String, String> paramMap = new HashMap<>();
//            paramMap.put("orderid", busOrder.getOrderNumber());
//            paramMap.put("code", "123456");
//            try {
//                SmsUtil.sendSms(req.getPhone(), "SMS_217429256", paramMap);
//            } catch (Exception e) {
//                log.error("巴士发送短信失败 [params : {}]", toJson(paramMap), e);
//                throw new BusinessException(SystemError.AIREXPRESS_ORDER_60037, e.getMessage());
//            }
    	}
    	return newResult();
    }
    
    /**
     * 供应商确认巴士订单
     * @return
     */
    @Override
    public Result<Void> supplieConfirmOrder(BusOrderSupplieConfirmReq req, Long userId) {
    	validateArgs(req);
    	
    	BusOrder entity = busOrderMapper.assertExistSelectOneByKey("order_number", req.getSaleNumber());
    	fillUpdateEntityUserId(entity, userId);
    	entity.setScheduledStatus(req.getReserveStatus());
    	
    	busOrderMapper.assertUpdateById(entity);
    	
    	return newResult();
    }


    /**
     * 根据币种名称获取汇率
     *
     * @param currencySy
     * @return
     */
    private BigDecimal getCrmExchangeRateByName(String currencySy) {
        MainDataCurrencyListReq mainDataCurrencyListReq = new MainDataCurrencyListReq();
        mainDataCurrencyListReq.setName(currencySy);
        PageResponse<MainDataCurrencyListDTO> list = mainDataCurrencyService.list(mainDataCurrencyListReq);
        if (com.baomidou.mybatisplus.core.toolkit.CollectionUtils.isEmpty(list.getRecords())) {
            throw new BusinessException(SystemError.AIREXPRESS_ORDER_60003);
        }
        return list.getRecords().get(0).getCrmExchangeRate();
    }



    /**
     * 生成巴士销售编号=B+部门代码+员工编号+年后2位+月日4位+3位随机数字
     *
     * @param userId
     * @return
     */
    @Override
    public String buildOrderNumber(Long userId, LocalDateTime nowLocalDateTime) {
        UserDTO userDTO = sysUserService.loadUserByParam(userId, 1);
        String employeeNumber = userDTO.getEmployeeNumber();
        SysDepartmentDTO sysDepartmentDTO = sysDepartmentService.queryOne(userDTO.getDeptId());
        String deptCode = sysDepartmentDTO.getDeptCode();
        String yearCode = String.valueOf(nowLocalDateTime.getYear()).substring(2, 4);
        String monthCode = StringUtils.leftPad(String.valueOf(nowLocalDateTime.getMonthValue()), 2, "0");
        String dayCode = StringUtils.leftPad(String.valueOf(nowLocalDateTime.getDayOfMonth()), 2, "0");
        String randomNumber = String.valueOf((int) ((Math.random() * 9 + 1) * 100));
        StringBuilder orderNumberSb = new StringBuilder();
        orderNumberSb.append("B").append(deptCode).append(employeeNumber).append(yearCode).append(monthCode).append(dayCode).append(randomNumber);
        return orderNumberSb.toString();
    }
    
    /**
     * 生成收款单号:
     * SKD+年後2位+月日4位+時分秒6位+2位隨機數字
     */
    @Override
    public String generatorPaymentNumber(LocalDateTime nowLocalDateTime) {
        String yearCode = String.valueOf(nowLocalDateTime.getYear()).substring(2, 4);
        String monthCode = StringUtils.leftPad(String.valueOf(nowLocalDateTime.getMonthValue()), 2, "0");
        String dayCode = StringUtils.leftPad(String.valueOf(nowLocalDateTime.getDayOfMonth()), 2, "0");
        String hourCode = StringUtils.leftPad(String.valueOf(nowLocalDateTime.getHour()), 2, "0");
        String minuteCode = StringUtils.leftPad(String.valueOf(nowLocalDateTime.getMinute()), 2, "0");
        String secondCode = StringUtils.leftPad(String.valueOf(nowLocalDateTime.getSecond()), 2, "0");
        String randomNumber = String.valueOf((int) ((Math.random() * 9 + 1) * 10));
        StringBuilder orderNumberSb = new StringBuilder();
        orderNumberSb.append("SKD").append(yearCode).append(monthCode).append(dayCode).append(hourCode)
                .append(minuteCode).append(secondCode).append(randomNumber);
        return orderNumberSb.toString().toUpperCase();
    }
    
    /**
     * 查询订单保险信息
     * @param orderId
     * @return
     */
    @Override
    public Result<BusOrderInsuranceDTO> findInsuranceByOrder(Long orderId) {
    	BusOrderInsuranceDTO dto = busOrderInsuranceMapper.selectOneByKey(BusOrderInsuranceDTO.class, "order_id", orderId);
    	return newResult(dto);
    }

    @Override
    public Result<List<MyBusOrderDTO>> recentToNow(LocalDateTime recent, LocalDateTime now) {
        List<BusOrder> orderList = baseMapper.selectList(Wrappers.<BusOrder>lambdaQuery()
                .eq(BusOrder::getIsDeleted,IsDeletedCode.NO.getCode())
                .ge(recent != null,BusOrder::getGmtModified, recent)
                .le(BusOrder::getGmtModified, now));

        List<MyBusOrderDTO> result = new ArrayList<>();
        for (BusOrder busOrder : orderList) {
            MyBusOrderDTO orderDTO = EntityUtil.copy(busOrder, MyBusOrderDTO.class);
            BusLineDTO busLineDTO = busLineService.queryByLineId(busOrder.getLineId());
            if(busLineDTO != null) {
                busLineDTO.setEstimatedTime(busLineDTO.getEstimatedTime());
            }
            result.add(orderDTO);
        }
        return Result.success(result);
    }

    @Override
    public List<BusOrderDTO> queryOrderDTOList(LocalDateTime start, LocalDateTime end) {
        return EntityUtil.copyList(baseMapper.selectList(Wrappers.<BusOrder>lambdaQuery()
                .eq(BusOrder::getIsDeleted, IsDeletedCode.NO.getCode())
                .ge(BusOrder::getGmtCreate, start)
                .le(BusOrder::getGmtCreate, end)),BusOrderDTO.class);
    }

    /**
     * 校验支付金额是否小于应收金额
     *
     * @param amountCountHKD   支付金额
     * @param receivableAmount 应收价格
     */
    private void checkAmount(BigDecimal amountCountHKD, BigDecimal receivableAmount) {
        if (amountCountHKD.compareTo(receivableAmount) < 0) {
            // 支付价格小于应收价格
            throw new BusinessException(SystemError.AIREXPRESS_ORDER_60004);
        }
    }


    /**
     * 使用和更新crm会员积分
     *
     * @param busOrder
     * @param readyMoney                             实收金额(现金，信用卡)
     * @param user
     * @param busOrderCollectionThirdList
     */
    private void useAndUpdateCrmMemberPoints(BusOrder busOrder, BigDecimal readyMoney, Long userId, List<BusOrderCollection> busOrderCollectionThirdList) {
        // 更新CRM会员积分记录
        log.info("【机场快线订单】会员信息,使用积分:{}, 查询类型:{},查询号:{},证书类型:{}", busOrder.getUsingPoints(), busOrder.getMemberQueryType(), busOrder.getMemberQueryCode(), busOrder.getMemberQueryCertificatesType());
        if (busOrder.getUsingPoints() != null && busOrder.getUsingPoints() > 0) {
            // 获取人民币兑港币汇率
            BigDecimal crmExchangeRateCNY = getCrmExchangeRateByName("CNY");
            ContactQueryDTO contactQuery;
            try {
                CrmMemberQueryReq crmMemberQueryReq = new CrmMemberQueryReq(busOrder.getMemberQueryType(), busOrder.getMemberQueryCode(), busOrder.getMemberQueryCertificatesType().toString());
                contactQuery = crmMemberService.queryMember(crmMemberQueryReq);
                // 构建创建用户ID，人民币金额，加分点数
                String crmUserId = String.valueOf(userId).substring(0, 12);
                BigDecimal rmbAmount = readyMoney.divide(crmExchangeRateCNY, 2, BigDecimal.ROUND_HALF_UP);
                BigDecimal addPoints = readyMoney.divide(new BigDecimal(String.valueOf(CrmMemberProductPointsRateEnum.TRAFFIC_TYPE.getRate())), BigDecimal.ROUND_DOWN);
                CrmMemberUpdatePointsReq crmMemberUpdatePointsReq = new CrmMemberUpdatePointsReq();
                crmMemberUpdatePointsReq.setUpdateType(2);
                crmMemberUpdatePointsReq.setNumPoints(new BigDecimal(busOrder.getUsingPoints()));//do积分点数
                crmMemberUpdatePointsReq.setXCtsProdDesc("單項委託-火车巴士船票(机场快线)");//do板塊產品描述 (建議使用: 集團產品名稱 + “ – “ + 板塊產品名稱, 例如: 港澳参团游 - 主题游)")
                crmMemberUpdatePointsReq.setTxnNum(busOrder.getOrderNumber() + "-1");//do交易編號 (如為旅行團交易, 目前我們的格式是 旅行團交易編號 + ‘-‘ + 序號, 例如: 01P08192131025A155506-1
                crmMemberUpdatePointsReq.setAmtVal(readyMoney);
                crmMemberUpdatePointsReq.setXCtsRmbAmount(rmbAmount);
                crmMemberUpdatePointsReq.setCreateUserid(crmUserId);
                crmMemberUpdatePointsReq.setXCtsTxnOrgCode("219910000010");
                crmMemberUpdatePointsReq.setTxnChannelCd("16");
                crmMemberUpdatePointsReq.setXCtsTxnChnNum("211099000010");
                crmMemberUpdatePointsReq.setProdName("8821090000");
                crmMemberUpdatePointsReq.setXCtsProdCode("8821090300");
                crmMemberService.updatePoints(crmMemberUpdatePointsReq, contactQuery);
                // 新增-加积分记录
                if (readyMoney.compareTo(BigDecimal.ZERO) == -1) {
                    // 实收金额不能小于0
                    throw new BusinessException(SystemError.AIREXPRESS_ORDER_60020);
                }
                CrmMemberUpdatePointsReq crmMemberIncreasePointsReq = new CrmMemberUpdatePointsReq();
                crmMemberIncreasePointsReq.setUpdateType(1);
                crmMemberIncreasePointsReq.setNumPoints(addPoints);//do积分点数
                crmMemberIncreasePointsReq.setXCtsProdDesc("單項委託-火车巴士船票(机场快线)");//do板塊產品描述 (建議使用: 集團產品名稱 + “ – “ + 板塊產品名稱, 例如: 港澳参团游 - 主题游)")
                crmMemberIncreasePointsReq.setTxnNum(busOrder.getOrderNumber() + "-2");//do交易編號 (如為旅行團交易, 目前我們的格式是 旅行團交易編號 + ‘-‘ + 序號, 例如: 01P08192131025A155506-1
                crmMemberIncreasePointsReq.setAmtVal(readyMoney);
                crmMemberIncreasePointsReq.setXCtsRmbAmount(rmbAmount);
                crmMemberIncreasePointsReq.setCreateUserid(crmUserId);
                crmMemberIncreasePointsReq.setXCtsTxnOrgCode("219910000010");
                crmMemberIncreasePointsReq.setTxnChannelCd("16");
                crmMemberIncreasePointsReq.setXCtsTxnChnNum("211099000010");
                crmMemberIncreasePointsReq.setProdName("8821090000");
                crmMemberIncreasePointsReq.setXCtsProdCode("8821090300");
                crmMemberService.updatePoints(crmMemberIncreasePointsReq, contactQuery);
                // 新增CRM会员付款方式
                BusOrderCollection busOrderCollection = new BusOrderCollection();
                busOrderCollection.setId(SnowflakeIdWorker.nextId());
                busOrderCollection.setOrderId(busOrder.getId());
                busOrderCollection.setCollectionAmount(readyMoney);
                busOrderCollection.setStandardAmount(rmbAmount);
                busOrderCollection.setCollectionWayId(1372459145921458178L); //支付方式：CRM星賞會積分
                busOrderCollection.setCollectionWay("星賞會積分");
                busOrderCollection.setIsDeleted(IsDeletedCode.NO.getCode());
                busOrderCollection.setCreateId(userId);
                busOrderCollection.setGmtCreate(busOrder.getGmtModified());
                busOrderCollection.setModifiedId(userId);
                busOrderCollection.setGmtModified(busOrder.getGmtModified());
                busOrderCollectionThirdList.add(busOrderCollection);
            } catch (Exception e) {
                if (e instanceof BusinessException) {
                    throw e;
                } else {
                    throw new BusinessException(SystemError.AIREXPRESS_ORDER_60009);
                }
            }
        }
    }



    private int insertReceipt(BusOrder busOrder, Long userId, LocalDateTime nowLocalDateTime, Long salesmanId) {
        UserDTO userDTO = sysUserService.loadUserByParam(salesmanId, 1);
        SysDepartmentDTO sysDepartmentDTO = sysDepartmentService.queryOne(userDTO.getDeptId());
        //生成收据单号
        String receiptNumber = generatorReceiptNumber(userDTO, sysDepartmentDTO, nowLocalDateTime);
        BusOrderReceipt busOrderReceipt = new BusOrderReceipt();
        busOrderReceipt.setId(SnowflakeIdWorker.nextId());
        busOrderReceipt.setOrderId(busOrder.getId());
        busOrderReceipt.setReceiptNo(receiptNumber);
        busOrderReceipt.setBranch(sysDepartmentDTO.getTitle());
        busOrderReceipt.setGuest(busOrder.getContactName());
        busOrderReceipt.setPhone(busOrder.getContactMobileAreaCode() + "-" + busOrder.getContactMobile());
        busOrderReceipt.setIsDeleted(IsDeletedCode.NO.getCode());
        busOrderReceipt.setCreateId(userId);
        busOrderReceipt.setGmtCreate(nowLocalDateTime);
        busOrderReceipt.setModifiedId(userId);
        busOrderReceipt.setGmtModified(nowLocalDateTime);
        return busOrderReceiptMapper.insert(busOrderReceipt);
    }


    /**
     * 生成收據號碼：門市編號+員工編號+年後2位+月日4位+B+時分秒6位+（S），
     * 例如：XS-C07884-200407-B-110008（S）
     *
     * @param userDTO
     * @return
     */
    private String generatorReceiptNumber(UserDTO userDTO, SysDepartmentDTO sysDepartmentDTO, LocalDateTime nowLocalDateTime) {
        String symbol = "-";
        String employeeNumber = userDTO.getEmployeeNumber();
        String deptCode = sysDepartmentDTO.getDeptCode();
        String yearCode = String.valueOf(nowLocalDateTime.getYear()).substring(2, 4);
        String monthCode = StringUtils.leftPad(String.valueOf(nowLocalDateTime.getMonthValue()), 2, "0");
        String dayCode = StringUtils.leftPad(String.valueOf(nowLocalDateTime.getDayOfMonth()), 2, "0");
        String hourCode = StringUtils.leftPad(String.valueOf(nowLocalDateTime.getHour()), 2, "0");
        String minuteCode = StringUtils.leftPad(String.valueOf(nowLocalDateTime.getMinute()), 2, "0");
        String secondCode = StringUtils.leftPad(String.valueOf(nowLocalDateTime.getSecond()), 2, "0");
        StringBuilder receiptNumberSb = new StringBuilder();
        receiptNumberSb.append("XS").append(symbol).append(deptCode).append(symbol)
                .append(employeeNumber).append(symbol)
                .append(yearCode).append(symbol)
                .append(monthCode).append(symbol)
                .append(dayCode).append(symbol).append("-B-")
                .append(hourCode).append(symbol)
                .append(minuteCode).append(symbol)
                .append(secondCode).append(symbol)
                .append("（S）");
        return receiptNumberSb.toString();
    }
    
    /**
     * 确认退款对接财务中心
     */
    private void confirmRefundToFinance(BusOrderRefund refundEntity, Long userId) {
    	BillOperateRefundReq callReq = new BillOperateRefundReq();
    	callReq.setBillNumber(refundEntity.getRefundNumber());
        callReq.setBusinessType(SystemBusinessType.BUS_TICKET.getCode());
        callReq.setUserId(userId);
        iFinanceBillService.operateRefund(callReq);
	}
    
    /**
     * 下单支付成功后，优惠相关处理
     */
    private void payOrderHandleDiscounts(BusOrderPayHandleReq req, BusOrder busOrder, Long userId, List<BusOrderCollection> collectionList
    		, BusProductDTO busProductDTO, BusOrderPayHandleInfoDTO handleInfoDTO) {
    	//银联优惠
    	if (BConst.ONE.equals(req.getIsUnionpayDiscount())) {
        	if (busOrder.getUsingPoints() != null || Assist.isNotBlank(busOrder.getCouponNumber())) {
        		//使用了会员积分或优惠券，无法使用银联优惠
        		throw new BusinessException(SystemError.AIREXPRESS_ORDER_60025);
        	}
        	
        	//查询银联优惠
        	OperateBankPreferenceQueryDTO bankPreferenceDTO = findBankPreference(busOrder, req, Assist.findFirst(collectionList));
        	
        	//创建收款明细
        	BusOrderCollection entity = fillDefaultOrderCollection(busOrder, userId, bankPreferenceDTO.getDiscount(), BusConst.PAY_WAY_ID_BANK_DISCOUNTS, BusConst.PAY_WAY_NAME_BANK_DISCOUNTS);
        	entity.setIsUnionpayDiscount(req.getIsUnionpayDiscount());
        	entity.setUnionpayDiscountId(req.getUnionpayDiscountId());
        	collectionList.add(entity);
        	
        	//扣减银优惠
        	deductBankPreference(busOrder, bankPreferenceDTO, userId, busProductDTO, entity);
        	
        	handleInfoDTO.setBankDiscountsBankId(bankPreferenceDTO.getBankId());
        	handleInfoDTO.setBankDiscountsBankName(bankPreferenceDTO.getBankName());
    	} else {  //推广码或积分
        	//积分
        	if (busOrder.getUsingPoints() != null) {
        		
        	}
        	
        	//推广码
        	if (Assist.isNotBlank(busOrder.getCouponNumber())) {
        		//查询推广码
        		OperatePromotionQueryDTO promotionDTO = findPromotionCode(busOrder);
        		busOrder.setCouponId(promotionDTO.getId());
        		
        		//创建收款明细
        		BusOrderCollection entity = fillDefaultOrderCollection(busOrder, userId, promotionDTO.getReductionAmount(), BusConst.PAY_WAY_ID_PROMOTION_CODE, BusConst.PAY_WAY_NAME_PROMOTION_CODE);
        		collectionList.add(entity);
        		
        		//扣减推广码
        		deductPromotionCode(busOrder, promotionDTO, userId, busProductDTO, entity);
        		
        		handleInfoDTO.setPromotionCodeDepartmentId(promotionDTO.getDepartmentId());
        		handleInfoDTO.setPromotionCodeDepartmentName(promotionDTO.getDepartmentName());;
        	}
        }
	}

    /**
     * 下单支付成功后，对接供应商
     */
    private void payOrderToSupplier(Long userId, BusOrder busOrder, BusProductDTO busProduct, List<BusOrderTourist> touristList
    		, Map<Integer, BusOrderCost> busOrderCostMap, boolean isConfirm, MainDataManualSystemDTO manualSystemDto, UserDTO userDTO) {
    	//总金额
    	BigDecimal totalFee = BigDecimal.ZERO;
    	//币种ID
    	Long currencyId = null;
    	//币种
    	String currency = null;
    	
    	SupplierOrderSystemBusAddReq callReq = new SupplierOrderSystemBusAddReq();
    	callReq.setSupplierOrderType("2");
    	callReq.setBusinessType(SystemBusinessType.BUS_TICKET.getCode());
    	callReq.setReserveTypeId(SupplierReserveTypeEnum.BUS.getId());
    	callReq.setProductType(busOrder.getProductType());
    	callReq.setSaleNumber(busOrder.getOrderNumber());
    	callReq.setProductName(packProductName(busProduct));
    	//二次确认
    	if (isConfirm) {
    		callReq.setConfirmStatus(SupplierConfirmStatus.UN_CONFIRM.getCode());
    	} else {  //立即确认
    		callReq.setConfirmStatus(SupplierConfirmStatus.CONFIRMED.getCode());
    	}
    	callReq.setConfirmTime(LocalDateTime.now());
    	callReq.setSupplierOrderNumber(busOrder.getOrderNumber());
    	callReq.setReserveStatus(busOrder.getScheduledStatus());
    	callReq.setSaleType(SalesMethod.SINGLE_SALE.getCode());
    	if (userDTO != null) {
    		callReq.setOriginalSaleNumber(Assist.toString(userDTO.getDeptId()));
    		callReq.setDepartmentId(userDTO.getDeptId());
    		callReq.setDepartment(userDTO.getDept());
    	}
    	
    	List<SupplierSystemOrderBusAddReq> orderCallReqList = new ArrayList<>();
    	SupplierSystemOrderBusAddReq orderCallReq = new SupplierSystemOrderBusAddReq();
    	orderCallReq.setOrderId(busOrder.getId());
    	
    	if (busProduct != null) {
    		callReq.setSupplierId(busProduct.getSupplierId());    	
    		callReq.setSupplierName(busProduct.getSupplierName());
    		callReq.setProductNumber(busProduct.getProductCode());
    		
    		orderCallReq.setSuitablePeople(busProduct.getIntendedForName());;
    	}
    	
    	if (manualSystemDto != null) {
    		callReq.setSupplierId(manualSystemDto.getSupplierId());    	
    		callReq.setSupplierName(manualSystemDto.getSupplierName());
    	}
    	
    	List<SupplierSystemOrderBusTicketAddReq> touristCallReqList = new  ArrayList<>();
    	
    	if (Assist.isNotEmpty(touristList)) {
    		for (BusOrderTourist tourist : touristList) {
    			SupplierSystemOrderBusTicketAddReq touristCallReq = new SupplierSystemOrderBusTicketAddReq();
    			touristCallReq.setBusId(null);
    			touristCallReq.setOrderId(busOrder.getId());
    			touristCallReq.setGoLocationJson(Assist.buildJson("id", busOrder.getDepartureCityId(), "name", busOrder.getDepartureCityName()));
    			touristCallReq.setDesLocationJson(Assist.buildJson("id", busOrder.getArriveCityId(), "name", busOrder.getArriveCityName()));
    			touristCallReq.setBusNumber(busOrder.getShiftCode());
    			touristCallReq.setStartTime(DateUtil.toLocalDateTime(busOrder.getEffectiveTime(), busOrder.getDepartureTime()));
    			touristCallReq.setEndTime(null);
    			touristCallReq.setTouristId(tourist.getId());
    			touristCallReq.setTouristName(tourist.getSurname());
    			touristCallReq.setTouristTypeId(Assist.toLong(tourist.getTouristType()));
    			touristCallReq.setTouristType(null);
    			
    			//旅客类型
    			Integer touristTypeId = Assist.toInteger(tourist.getTouristType());
    			if (touristTypeId != null) {
    				BusOrderCost busOrderCost = busOrderCostMap.get(touristTypeId);
    				if (busOrderCost != null) {
    					touristCallReq.setSinglePrice(busOrderCost.getCostPrice());
    					totalFee = Assist.add(totalFee, busOrderCost.getCostPrice());
    					if (currencyId == null) {
    						currencyId = busOrderCost.getCostCurrencyId();
    					}
    					if (currency == null) {
    						currency = busOrderCost.getCostCurrency();
    					}
    				}
    			}
    			
    			touristCallReqList.add(touristCallReq);
			}
    	}
    	orderCallReq.setSupplierSystemOrderBusTicketAddReqList(touristCallReqList);
    	
    	callReq.setPayableAmount(totalFee);
    	callReq.setTotalFee(totalFee);
    	callReq.setCurrencyId(currencyId);
    	callReq.setCurrency(currency);
    	
    	orderCallReqList.add(orderCallReq);
    	callReq.setSupplierSystemOrderBusAddReqList(orderCallReqList);
    	
    	supplierOrderService.addSystemBus(callReq, userId).ok();
    }
    
    /**
     * 下单支付成功后，对接财务中心
     */
    private void payOrderToFinance(BusOrder orderEntity, List<BusOrderCollection> collectionList, Long userId, BusProductDTO busProductDTO
    		, BusOrderPayHandleReq req, BusOrderPayHandleInfoDTO handleInfoDTO) {
		if (Assist.isEmpty(collectionList)) {
			return;
		}
		
		//销售人员信息
		UserDTO userDTO = Assist.ifNotNullFn(orderEntity.getSalesmanId(), sysUserService::queryCacheUser);
		
		//认款参数列表
		List<BillAddCollectionReq> addCallReqList = new ArrayList<>();
		//挂账参数列表
		List<UseQuotaReq> quotaCallReqList = new ArrayList<>();
		
		for (BusOrderCollection collectionEntity : collectionList) {
			UseQuotaReq quotaCallReq = null;

			//挂账
			if (BusConst.PAY_WAY_ID_ACCOUNTS.equals(collectionEntity.getCollectionWayId())) {
				quotaCallReq = new UseQuotaReq();
				quotaCallReq.setAccountType(1);

				//代理
				if (BusConst.CLIENT_TYPE_AGENT.equals(orderEntity.getClientType())) {
					quotaCallReq.setAccountId(orderEntity.getAgencyId());
				} else if (BusConst.CLIENT_TYPE_BIG.equals(orderEntity.getClientType())) {  //大客户
					quotaCallReq.setAccountId(orderEntity.getBigClientId());
					quotaCallReq.setBigClientId(orderEntity.getBigClientId());
					quotaCallReq.setBigClientName(orderEntity.getBigClientName());
				}
			} else if (BusConst.PAY_WAY_ID_ACCOUNTS_INNER.equals(collectionEntity.getCollectionWayId())) {  //内部挂账
				quotaCallReq = new UseQuotaReq();
				quotaCallReq.setAccountType(2);
				quotaCallReq.setTripNumber(req.getTripNumber());

				UserDTO userDto = sysUserService.queryCacheUser(orderEntity.getSalesmanId());
				notNull(userDto, SystemError.USER_1002);
				quotaCallReq.setDeptId(userDto.getDeptId());
			} else if (BusConst.PAY_WAY_ID_PROMOTION_CODE.equals(collectionEntity.getCollectionWayId())) {  //推广码走内部挂账
				quotaCallReq = new UseQuotaReq();
				quotaCallReq.setAccountType(2);
				quotaCallReq.setDeptId(handleInfoDTO.getPromotionCodeDepartmentId());
			} else if (BusConst.PAY_WAY_ID_BANK_DISCOUNTS.equals(collectionEntity.getCollectionWayId())) {  //银联优惠走外部挂账
				quotaCallReq = new UseQuotaReq();
				quotaCallReq.setAccountType(1);
				quotaCallReq.setAccountId(handleInfoDTO.getBankDiscountsBankId());
				quotaCallReq.setBigClientId(handleInfoDTO.getBankDiscountsBankId());
				quotaCallReq.setBigClientName(orderEntity.getBigClientName());
			} else if (BusConst.PAY_WAY_ID_INTEGRAL.equals(collectionEntity.getCollectionWayId())) {  //积分走集团挂账
				quotaCallReq = new UseQuotaReq();
				
			} else {  //其余收款方式走认款
				BillAddCollectionReq addCallReq = new BillAddCollectionReq();
				fillData(addCallReq, collectionEntity, orderEntity, busProductDTO, userDTO, userId);
				addCallReqList.add(addCallReq);
				continue;
			}
			
			//除认款外，其余挂账
			if (quotaCallReq != null) {
				fillData(quotaCallReq, userId, collectionEntity, orderEntity, busProductDTO);
				quotaCallReqList.add(quotaCallReq);
			}
		}
		
		//认款
		if (Assist.isNotEmpty(addCallReqList)) {
			iFinanceBillService.addCollection(addCallReqList).ok();
		}
		
		//挂账
		if (Assist.isNotEmpty(quotaCallReqList)) {
    		financeOnAccountCurrencyQuotaService.useQuota(quotaCallReqList).ok();
    	}
    }
    
    /**
     * 下单支付成功后，对接保险
     */
    private void payOrderToInsurance(BusOrder orderEntity, List<BusOrderTourist> touristList, Long userId, BusOrderInsurance busOrderInsurance) {
    	if (busOrderInsurance == null)
    		return;
    	InsuranceUnderwritingReq callReq = new InsuranceUnderwritingReq();
    	AcceptUnderReq acceptReq = new AcceptUnderReq();
    	callReq.setAcceptReqList(Assist.asList(acceptReq));
        
        //計劃資訊列表
        List<PlanConsult> guItemAcciDetailDtoList = new ArrayList<>();
        PlanConsult guItemAcciDetailDto = new PlanConsult();
//        guItemAcciDetailDto.setItemDetailNo(insurance.getMainDataId().toString());
        guItemAcciDetailDto.setRationType(busOrderInsurance.getRationType());
        guItemAcciDetailDto.setRemark("01");
        guItemAcciDetailDtoList.add(guItemAcciDetailDto);
        
        //旅客参保信息
        if (Assist.isNotEmpty(touristList)){
        	List<InsuredInfo> guItemAcciListDtoList = new ArrayList<>();
        	//被保人資訊列表
        	for (BusOrderTourist tourist : touristList){
        		if (tourist.getInsuranceId() == null) {
        			continue;
        		}
        		
        		//投保人
        		if (tourist.getId().equals(busOrderInsurance.getPolicyHolderId())) {
        			//投保人
        	        ApplicantInfo appliGuRelatedPartyDto = new ApplicantInfo();
        	        if (tourist.getBirthday() != null) {
        	        	appliGuRelatedPartyDto.setAge(tourist.getBirthday().until(LocalDate.now()).getYears()+"");
        	        	appliGuRelatedPartyDto.setBirthDate(DateUtil.fmtLocalDate(tourist.getBirthday(),"yyyy-MM-dd"));
        	        }
        	        appliGuRelatedPartyDto.setEmail("aa@163.com");
        	        appliGuRelatedPartyDto.setIdentifyNumber(tourist.getCertificatesNumber());
//        	        appliGuRelatedPartyDto.setIdentifyType(PacificUtil.getIdentifyType(tourist.getCertificatesType()));
        	        appliGuRelatedPartyDto.setIdentifyType("00");
        	        appliGuRelatedPartyDto.setSex(Assist.toString(tourist.getGender()));
        	        appliGuRelatedPartyDto.setMobilePhone("123456");
        	        appliGuRelatedPartyDto.setInsuredName(Assist.join(tourist.getSurname(), tourist.getName()));
        	        appliGuRelatedPartyDto.setInsuredEName(appliGuRelatedPartyDto.getInsuredName());
        	        acceptReq.setAppliGuRelatedPartyDto(appliGuRelatedPartyDto);
        		}
        		
        		//受保人
        		if (tourist.getInsuranceId() != null) {
        			InsuredInfo insuredInfo = new InsuredInfo();
        	        if (tourist.getBirthday() != null) {
        	        	insuredInfo.setAge(tourist.getBirthday().until(LocalDate.now()).getYears()+"");
        	        	insuredInfo.setBirthday(DateUtil.fmtLocalDate(tourist.getBirthday(),"yyyy-MM-dd"));
        	        }
        	        insuredInfo.setIdentifyNoA(tourist.getCertificatesNumber());
//        	        insuredInfo.setIdentifyTypeA(PacificUtil.getIdentifyType(tourist.getCertificatesType()));
        	        insuredInfo.setIdentifyTypeA("00");
        	        insuredInfo.setSex(Assist.toString(tourist.getGender()));
        	        insuredInfo.setClientCName(Assist.join(tourist.getSurname(), tourist.getName()));
        	        guItemAcciListDtoList.add(insuredInfo);
        		}
        	}
        	
        	//无人参保
        	if (Assist.isEmpty(guItemAcciListDtoList)) {
        		return;
        	}
        	
        	acceptReq.setGuItemAcciListDtoList(guItemAcciListDtoList);
        }
        
        acceptReq.setStartDate(DateUtil.fmtLocalDate(busOrderInsurance.getBeginDate(),"yyyy-MM-dd"));
        acceptReq.setEndDate(DateUtil.fmtLocalDate(busOrderInsurance.getEndDate(),"yyyy-MM-dd"));
        acceptReq.setStartPlace(busOrderInsurance.getDeparturePlace());
        acceptReq.setEndPlace(busOrderInsurance.getDestination());
        
    	callReq.setOrderNumber(orderEntity.getOrderNumber());
    	callReq.setBusinessType(SystemBusinessType.BUS_TICKET.getCode());
    	callReq.setTotalFee(busOrderInsurance.getTotalAmount());
    	callReq.setUserId(userId);
    	callReq.setInsuranceId(busOrderInsurance.getMainDataId());
    	
    	try {
    		InsuranceInsuredDTO insuranceInsuredDTO = iInsuranceService.sendProposalContent(callReq);
    		if (insuranceInsuredDTO != null && Assist.isNotBlank(insuranceInsuredDTO.getInsuranceReceiptNumber())) {
    			fillUpdateEntityUserId(busOrderInsurance, userId);
    			busOrderInsurance.setInsuranceNumber(insuranceInsuredDTO.getInsuranceReceiptNumber());
    			busOrderInsuranceMapper.updateById(busOrderInsurance);
    		}
    	}catch (Exception e){
    		log.error("下单支付成功后，对接保险异常", e);
    		throw new BusinessException(SystemError.CUSTOM_ORDER_4026);
    	}
    }
    
    /**
     * 创建默认的收款明细
     */
    private BusOrderCollection fillDefaultOrderCollection(BusOrder busOrder, Long userId, BigDecimal amount, Long collectionWayId, String collectionWay) {
    	BusOrderCollection entity = newCreateEntityUserId(BusOrderCollection.class, null, userId);
    	entity.setOrderId(busOrder.getId());
    	entity.setCollectionNumber(generatorPaymentNumber(LocalDateTime.now()));
    	entity.setCurrencyId(BusConst.CURRENCY_ID_HKD);
    	entity.setCurrency(BusConst.CURRENCY_NAME_HKD);
    	entity.setCollectionAmount(amount);
    	entity.setStandardAmount(amount);
    	entity.setCollectionWayId(collectionWayId);
    	entity.setCollectionWay(collectionWay);
    	entity.setSalerId(busOrder.getSalesmanId());
    	entity.setSalerName(busOrder.getSalesmanName());
//    	entity.setStatus(OrderCollectionStatus.UN_REJECT.getCode());
    	entity.setExchangeRate(BigDecimal.ONE);
    	return entity;
	}
    
    /**
     * 查询推广码 
     * @return
     */
    private OperatePromotionQueryDTO findPromotionCode(BusOrder busOrder) {
    	OperatePromotionConformReq callReq = new OperatePromotionConformReq();
    	callReq.setActivityCode(busOrder.getCouponNumber());
    	callReq.setTotalPaidIn(busOrder.getOrderAmount());
    	callReq.setBusinessType(SystemBusinessType.BUS_TICKET.getCode());
    	callReq.setRelationId(busOrder.getBusId());
    	callReq.setChannelId(Assist.toLong(busOrder.getSource()));
//    	callReq.setDiscountObjectId(1l);
    	callReq.setUserId(busOrder.getSalesmanId());
    	return operatePromotionService.queryConform(callReq).okExist();
	}
    
    /**
     * 扣减推广码 
     */
    private void deductPromotionCode(BusOrder busOrder, OperatePromotionQueryDTO mainDto, Long userId, BusProductDTO busProductDTO
    		, BusOrderCollection collectionEntity) {
    	OperatePromotionDeductReq callReq = new OperatePromotionDeductReq();
    	callReq.setId(mainDto.getId());
    	callReq.setTotalPaidIn(busOrder.getOrderAmount());
    	callReq.setBusinessType(SystemBusinessType.BUS_TICKET.getCode());
    	callReq.setRelationId(busProductDTO.getId());
    	callReq.setProductNumber(busProductDTO.getProductCode());
    	callReq.setProductName(packProductName(busProductDTO));
    	callReq.setDiscountObjectId(null);
    	callReq.setChannelId(Assist.toLong(busOrder.getSource()));
    	operatePromotionService.deduct(callReq, createFakeTokenUser(userId)).ok();
    }
    
    /**
     * 查询银联优惠
     * @return
     */
    private OperateBankPreferenceQueryDTO findBankPreference(BusOrder busOrder, BusOrderPayHandleReq req, BusOrderCollection collectionEntity) {
    	OperateBankConformQueryReq callReq = new OperateBankConformQueryReq();
    	callReq.setId(req.getUnionpayDiscountId());
    	callReq.setBusinessType(SystemBusinessType.BUS_TICKET.getCode());
    	callReq.setRelationId(busOrder.getBusId());
    	callReq.setChannelId(Assist.toLong(busOrder.getSource()));
    	callReq.setUserId(busOrder.getSalesmanId());
    	callReq.setTotalPaidIn(busOrder.getOrderAmount());
    	callReq.setCardNumber(collectionEntity.getPayer());
    	return operateBankPreferenceService.queryConform(callReq).okExist();
    }
    
    /**
     * 扣减银联优惠
     */
    private void deductBankPreference(BusOrder busOrder, OperateBankPreferenceQueryDTO mainDto, Long userId, BusProductDTO busProductDTO
    		, BusOrderCollection collectionEntity) {
    	OperateBankDeductReq callReq = new OperateBankDeductReq();
    	callReq.setCardNumber(null);
    	callReq.setId(mainDto.getId());
    	callReq.setTotalPaidIn(busOrder.getOrderAmount());
    	callReq.setBusinessType(SystemBusinessType.BUS_TICKET.getCode());
    	callReq.setRelationId(busProductDTO.getId());
    	callReq.setProductNumber(busProductDTO.getProductCode());
    	callReq.setProductName(packProductName(busProductDTO));
    	callReq.setDiscountObjectId(null);
    	callReq.setChannelId(Assist.toLong(busOrder.getSource()));

    	operateBankPreferenceService.deduct(callReq, createFakeTokenUser(userId));
    }
    
    /**
     * 封装产品名称
     */
    private String packProductName(BusProductDTO dto) {
    	if (dto == null)
    		return null;
    	return packProductName(dto.getBoardingStationName(), dto.getAlightingStationName());
    }
    
    /**
     * 封装产品名称
     */
    private String packProductName(String boardingStationName, String alightingStationName) {
    	return Assist.join(boardingStationName, " - ", alightingStationName);
	}
    
    private void fillData(UseQuotaReq quotaCallReq, Long userId, BusOrderCollection collectionEntity, BusOrder orderEntity, BusProductDTO busProductDTO) {
    	quotaCallReq.setUserId(userId);
		quotaCallReq.setBillNumber(collectionEntity.getCollectionNumber());
		quotaCallReq.setCurrencyId(collectionEntity.getCurrencyId());
		quotaCallReq.setCurrencyName(collectionEntity.getCurrency());
		quotaCallReq.setExchangeRate(Assist.toDouble(collectionEntity.getExchangeRate()));
		quotaCallReq.setAmount(collectionEntity.getCollectionAmount());
		quotaCallReq.setBusinessType(SystemBusinessType.BUS_TICKET.getCode());
		quotaCallReq.setCollectionWayId(collectionEntity.getCollectionWayId());
		quotaCallReq.setCollectionWayName(collectionEntity.getCollectionWay());
		quotaCallReq.setCollectionTypeId(null);
		quotaCallReq.setCollectionTypeName(null);
		quotaCallReq.setCollectionTime(collectionEntity.getGmtCreate());
		quotaCallReq.setCollectionVoucherJson(null);
		quotaCallReq.setSaleOrderNumber(orderEntity.getOrderNumber());
		quotaCallReq.setSaleOrderId(orderEntity.getId());
		quotaCallReq.setProductId(busProductDTO.getId());
		quotaCallReq.setProductNumber(busProductDTO.getProductCode());
		quotaCallReq.setProductName(packProductName(busProductDTO));
		quotaCallReq.setResourceInfo(Assist.asList(quotaCallReq.getProductName()));
		quotaCallReq.setSaleUserId(orderEntity.getSalesmanId());
		quotaCallReq.setSaleUserName(orderEntity.getSalesmanName());
		quotaCallReq.setTouristName(orderEntity.getContactName());
		quotaCallReq.setContactMobile(orderEntity.getContactMobile());
	}
    
    private void fillData(BillAddCollectionReq addCallReq, BusOrderCollection collectionEntity, BusOrder orderEntity, BusProductDTO busProductDTO
    		, UserDTO userDTO, Long userId) {
    	addCallReq.setBillNumber(collectionEntity.getCollectionNumber());
        addCallReq.setBusinessType(SystemBusinessType.BUS_TICKET.getCode());
        addCallReq.setCollectionWayId(collectionEntity.getCollectionWayId());
        addCallReq.setCollectionWayName(collectionEntity.getCollectionWay());
        addCallReq.setCollectionTypeId(CollectionTypeIdCode.FULL.getCode());
        addCallReq.setCollectionTypeName(CollectionTypeIdCode.FULL.getMsg());
        addCallReq.setCollectionAmount(collectionEntity.getCollectionAmount());
        addCallReq.setCurrencyId(collectionEntity.getCurrencyId());
        addCallReq.setCurrencyName(collectionEntity.getCurrency());
        addCallReq.setExchangeRate(collectionEntity.getExchangeRate().doubleValue());
        addCallReq.setCollectionTime(collectionEntity.getGmtCreate());
//        callReq.setCollectionVoucherJsonList(fileJsons); // 收款凭证
        addCallReq.setSaleOrderNumber(orderEntity.getOrderNumber());
        addCallReq.setSaleOrderId(orderEntity.getId());
        addCallReq.setProductId(Arrays.asList(busProductDTO.getId()));
        addCallReq.setProductName(packProductName(busProductDTO));
        addCallReq.setProductNumber(busProductDTO.getProductCode());
//        callReq.setResourceInfo(Arrays.asList(airportExpressInfoDTO.getTicketTypeNameCn()));
        
        if (userDTO != null) {
        	addCallReq.setSaleUserId(userDTO.getId());
        	addCallReq.setSaleUserName(userDTO.getFullName());
        	addCallReq.setSaleDeptId(userDTO.getDeptId());
        }
        addCallReq.setUserId(userId);
	}
}
